【问题标题】:Read sqlite data when a transaction is running (Android)事务运行时读取 sqlite 数据(Android)
【发布时间】:2014-12-24 12:10:51
【问题描述】:

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

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

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

我已经阅读了很多关于 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。

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

【问题讨论】:

    标签: android multithreading sqlite android-sqlite


    【解决方案1】:

    我解决了这个问题。

    我遵循了这些步骤。

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

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

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

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

    使用database.enableWriteAheadLogging()(仅api>=11),我的错误是你必须在所有连接中启用此模式,而不仅仅是在你的事务或你的写作中,所以我在我的openHelper类中添加了以下代码“ onOpen”方法。基于 Mozilla 在 github (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(),您将为其他线程提供使用数据库的机会。我没有看到将这种方法与beginTransactionbeginTransactionNonExclusive.

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

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 同步是为了避免竞争条件等...它会给我的情况增加更多的阻塞问题...我只需要读取数据库而不用担心我是否正在更新表。跨度>
      • 在这种情况下,您将不得不提出自己的逻辑。
      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          【解决方案5】:

          我建议看关闭同步 SQLITE 选项的方向(默认情况下,在 Android 中,当一个写入事务操作正在运行其他读取数据库查询时等待完成写入事务) 您应该在每次连接到此选项的数据库 tyrn 之前通过 db.exeqSql("PRAGMA synchronous = OFF") 因此,所有读取操作都会立即执行,但您会从数据库中获得一些过时的数据(您无法在结果数据中看到正在运行的写入事务正在插入数据库)

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多