在事务运行时读取sqlite数据(Android)

时间:2014-12-24 12:10:52

标签: android multithreading sqlite android-sqlite

我需要从数据库中读取一些数据,同时我在一个事务的另一个线程中加载一些数据。

我的所有读取其他表的线程都会停止,直到其他线程中的事务完成为止。

我需要能够从数据库中读取信息而不必担心其他线程。

我已经阅读了很多关于sqlite,android的信息...但是没有任何工作,总是我的查询参数被阻止。

我已经遵循了这个建议,因为@KevinGalligan在这个帖子(What are the best practices for SQLite on Android?)中解决了锁定和其他问题。

1)我只使用一个SQLiteOpenHelper(单例)

2)我从不关闭数据库

我试过了:

用以下方式开始交易:

database.execSQL("begin immediate transaction");

database.beginTransactionNonExclusive();

代替

database.beginTransaction();

无效,查询已被屏蔽。

我已经读过WAL(database.enableWriteAheadLogging()),但我需要支持api 9.

同时阅读任何其他解决方案的事务正在更新某些表吗?如果我的信息被弃用,我不在乎,不要阻止我的线程更重要。

5 个答案:

答案 0 :(得分:6)

我解决了这个问题。

我按照这个步骤。

解决数据库锁定和多线程使用数据库的问题(基于http://touchlabblog.tumblr.com/post/24474750219/single-sqlite-connection):

1)我只使用一个SQLiteOpenHelper(单例)。

2)永远不要关闭数据库。

为了能够在不阻止查询的情况下进行读写,我按照以下步骤操作:

使用database.enableWriteAheadLogging()(仅限api> = 11),我的错误是您必须在所有连接中启用此模式,不仅在您的交易或您的作品中,所以我将以下代码添加到我的openHelper类in" onOpen"方法。基于此github中的Mozilla代码(https://github.com/mozilla/mozilla-central/blob/9f2b8297b99d9d28038256b4f92a5aaa941749f1/mobile/android/base/db/TabsProvider.java)。

@SuppressLint("NewApi")
    @Override
     public void onOpen(SQLiteDatabase db) {

         // From Honeycomb on, it's possible to run several db
         // commands in parallel using multiple connections.
         if (Build.VERSION.SDK_INT >= 11) {
             try{
                 db.enableWriteAheadLogging();
             }catch(Exception e){
                 Log.e("onOpen", e.getMessage());
             }
         }
     }

使用此解决方案,我解决了在更新某些表时阻止读取的问题,但其他更新也被阻止了。如果你想解决这个问题,正如@commonsware所说:

在事务中使用yieldIfContendedSafely(),您将为其他线程提供使用数据库的机会。我没有看到使用此方法与beginTransaction或。{ beginTransactionNonExclusive

另一个有趣的读物是:What are the best practices for SQLite on Android?

答案 1 :(得分:2)

我认为您应该使用同步概念来避免您遇到的问题。

答案 2 :(得分:2)

如果您的数据加载工作不只是一个大规模的SQL事务,use yieldIfContendedSafely()允许您的其他线程在不同的点读取数据库。因此,例如,如果您正在进行某种批量数据加载,并且每100个插入执行一次事务,请在每100次插入循环的每次传递中调用yieldIfContendedSafely(),以便为其他线程提供机会使用数据库。

答案 3 :(得分:0)

android中的SQLite不是线程安全的,数据库将在执行操作时被锁定,这意味着你应该确保数据库操作只在一个线程中执行,并调用database.setTransactionSuccessful();在你的工作完成后结束交易。

答案 4 :(得分:0)

我建议在方向上关闭同步SQLITE选项(默认情况下,在Android中,当一个写入事务操作正在运行时,其他读取数据库查询正在等待完成写入事务) 您应该在每次连接到该选项的数据库类型之前,通过 \0 结果,所有读取操作将立即执行,但是您会从数据库中获取一些过时的数据(您无法在结果数据中看到正在运行的写事务正在插入到数据库中)