【问题标题】:SQLiteDatabase.endTransaction throws SQLiteDatabaseLockedExceptionSQLiteDatabase.endTransaction 抛出 SQLiteDatabaseLockedException
【发布时间】:2013-05-19 14:49:04
【问题描述】:

我的代码:

SQLiteDatabase db = ...;
db.beginTransaction();
try{
   db.update(...);

   db.setTransactionSuccessful();
}finally{
   db.endTransaction();
}

现在的问题是 endTransaction 偶尔抛出 SQLiteDatabaseLockedException,我不知道原因,也不知道如何重复同样的异常。

来自SQLiteDatabaseLockedException 我读到:

如果数据库引擎无法获取数据库锁则抛出 它需要完成它的工作。

我从beginTransaction读到:

以独占模式开始交易。

来自SQLite manual 我读到:

需要一个独占锁才能写入数据库文件。 文件上只允许有一个 EXCLUSIVE 锁,不允许有其他锁 任何种类都允许与独占锁共存。为了 最大化并发性,SQLite 致力于最小化 持有独占锁。

那么当我从 beginTransaction 持有排他锁时,如何在 endTransaction 中不获取 DB 锁? 发生这种情况的 Android 版本是 4.0.4(我有崩溃报告,但无法重复)。

需要说我在数据库上启用了SQLiteDatabase.enableWriteAheadLogging,也许这很重要?我的应用在多个线程中访问数据库。

无论如何,我想得到清楚的解释,并做一个简单的例子,可以重复条件重复问题,以便我可以真正解决。 谢谢。

【问题讨论】:

  • 不应该是:SQLiteDatabase db = new SQLiteDatabase();
  • 已更新为“...”以标记它已经初始化。
  • @PointerNull 你是如何解决这个问题的?

标签: android sqlite android-sqlite


【解决方案1】:

IMO 您的代码在单线程应用程序中是正确的,因此它必须是与 enableWriteAheadLogging 相关的问题。也许这会有所帮助:

SOURCE

... 用于执行查询的最大连接数 并行取决于设备内存和可能的其他 属性。

...

编写者应使用 beginTransactionNonExclusive() 或 beginTransactionWithListenerNonExclusive(SQLiteTransactionListener) 到 开始交易。非独占模式允许数据库文件处于 其他执行查询的线程可读。

...

【讨论】:

    【解决方案2】:

    据我所知,在 sqlite 的可序列化(默认)模式下,锁不是指不同的线程,而是指 connections(这种模式甚至对线程一无所知)。因此,如果您在多个线程中使用相同的连接(并且由一个 sqliteOpenHelper 实例生成的所有 SqliteDatabase 对象共享相同的连接),那么您将完全不受保护。

    如果您坚持多线程使用 Sqlite,请使用每个线程的连接或非数据库同步锁。我更喜欢带有单个线程锁的包装单例,以保护其每个类似事务的方法。但这取决于您的应用细节。

    请阅读此extensive answer 及其中的链接,了解有关 Sqlite 多线程的详细信息和最佳实践。

    【讨论】:

      猜你喜欢
      • 2015-07-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-24
      • 1970-01-01
      • 2014-11-23
      • 2013-05-30
      相关资源
      最近更新 更多