SQLiteDatabase.endTransaction抛出SQLiteDatabaseLockedException

时间:2013-05-18 22:08:34

标签: android sqlite android-sqlite

我的代码:

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

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

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

SQLiteDatabaseLockedException我读到:

  

如果数据库引擎无法获取数据库锁,则抛出该异常   它需要做好自己的工作。

我从beginTransaction读到:

  

在EXCLUSIVE模式下开始交易。

SQLite manual我读到:

  

为了写入数据库文件,需要一个EXCLUSIVE锁。   文件上只允许一个EXCLUSIVE锁,没有其他锁   任何种类都可以与EXCLUSIVE锁共存。为了   最大化并发性,SQLite可以最大限度地减少时间   持有独家锁。

那么当我从beginTransaction持有独占锁时,怎样才能在endTransaction中获取DB锁? 发生这种情况的Android版本是4.0.4(我有崩溃报告,但无法重复此操作)。

需要说我在数据库上启用了SQLiteDatabase.enableWriteAheadLogging,这可能很重要吗?我的应用程序以多个线程访问数据库。

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

2 个答案:

答案 0 :(得分:0)

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

SOURCE

  

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

     

...

     

作家应该使用beginTransactionNonExclusive()或   beginTransactionWithListenerNonExclusive(SQLiteTransactionListener)to   开始交易。非独占模式允许数据库文件   执行查询的其他线程可读。

     

...

答案 1 :(得分:0)

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

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

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