我的代码:
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,这可能很重要吗?我的应用程序以多个线程访问数据库。
无论如何,我想得到清楚的解释,并做一个简单的例子,可以重复重复问题的条件,这样我就可以做出真正的修复。 感谢。
答案 0 :(得分:0)
IMO您的代码在单个线程应用程序中是正确的,因此它必须是与enableWriteAheadLogging相关的问题。也许这可以提供帮助:
...用于执行查询的最大连接数 parallel取决于设备内存以及可能的其他内存 属性。
...
作家应该使用beginTransactionNonExclusive()或 beginTransactionWithListenerNonExclusive(SQLiteTransactionListener)to 开始交易。非独占模式允许数据库文件 执行查询的其他线程可读。
...
答案 1 :(得分:0)
正如我在sqlite的可序列化(默认)模式中所理解的,锁不是指不同的线程,而是指连接(这种模式甚至对线程一无所知)。因此,如果您在多个线程中使用相同的连接(以及由一个sqliteOpenHelper实例生成的所有SqliteDatabase对象共享相同的连接),则您完全不受保护。
如果您坚持多线程使用Sqlite,请使用每个线程的连接或非数据库同步锁。我更喜欢带有单个线程锁的包装器单例保护其每个类似事务的方法。但这取决于您的应用程序细节。
请阅读此extensive answer及其中的链接,了解Sqlite多线程的详细信息和最佳做法。