1

My code:

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

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

Now the problem is that endTransaction occasionally throws SQLiteDatabaseLockedException, and I don't know reason, or how to repeat same exception.

From SQLiteDatabaseLockedException I read:

Thrown if the database engine was unable to acquire the database locks it needs to do its job.

And from beginTransaction I read:

Begins a transaction in EXCLUSIVE mode.

From SQLite manual I read:

An EXCLUSIVE lock is needed in order to write to the database file. Only one EXCLUSIVE lock is allowed on the file and no other locks of any kind are allowed to coexist with an EXCLUSIVE lock. In order to maximize concurrency, SQLite works to minimize the amount of time that EXCLUSIVE locks are held.

So how can DB lock not be acquired in endTransaction when I hold exclusive lock from beginTransaction? Android version where this happens is 4.0.4 (I have crash report, but not able to repeat this).

Need to say that I enabled SQLiteDatabase.enableWriteAheadLogging on the DB, maybe it matters? My app accessess DB in multiple threads.

Anyway, I'd like to get clear explanation, and make simple example that can repeat conditions repeating the problem, so that I can make real fix. Thanks.

4

2 回答 2

0

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

资源

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

...

编写者应使用 beginTransactionNonExclusive() 或 beginTransactionWithListenerNonExclusive(SQLiteTransactionListener) 来启动事务。非独占模式允许执行查询的其他线程读取数据库文件。

...

于 2013-05-18T23:59:57.823 回答
0

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

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

请阅读这个广泛的答案和其中的链接,了解 Sqlite 多线程的详细信息和最佳实践。

于 2013-05-19T00:10:12.390 回答