我有一个应用程序(Android 2.2 Google API Level 8),它有多个活动从内容提供者那里提取数据(仅选择数据库访问)。它还有一个带有中央阻塞任务队列的服务,可以接受任何数据库写入任务;活动可以触发服务请求(作为意图),该请求将任务放在阻塞队列中,以便由单个线程顺序检索并执行。数据库大约 4mb。
服务使用一个数据库助手来调用与数据库交互的方法,包括写入数据库;所有 SQL 写入都在数据库助手中执行。
- 所有数据库写入都被事务包围。
- 所有数据库读取都在方法结束时关闭游标。
- 所有活动都没有数据库对象的句柄,它们只能通过内容提供者或服务进行通信。
- 任何 AlarmManager 触发的任务(如活动)仅使用该服务将适当的任务弹出到队列中。
- 该服务是唯一拥有数据库助手句柄的类。
- 所有数据库写入仅通过放置在队列中的任务执行;我已经彻底检查了任务执行是按顺序执行的,我很清楚避免并发写入 SQLite 数据库是必不可少的。
在一系列任务执行过程中,我在尝试写入由“开始事务”的任务执行触发的数据库时总是遇到一个或两个“数据库已锁定”错误。
在试图追踪锁定的来源时,我发现使用 dbhelper.inTransaction()、dbhelper.isLockedByThisThread()、dbhelper.isLockedByOtherThread() 并没有帮助,因为它们不会指示意外的数据库锁定。
我确实发现在早期检测锁定方面起作用的是使用 beginTransaction() 和 setTransactionSuccessful 创建一个方法,而无需任何实际的 SQL 编写代码,在将记录问题的 try catch 块中 - 始终由 beginTransaction() 触发。
我将这个数据库锁定陷阱放置在每个阻塞队列任务方法的任一侧,期望/希望我会找到一个在完成后使数据库处于锁定状态的单一罪魁祸首。我找不到一致的罪魁祸首。在从任务调用开始一直深入到数据库写入之后,我发现数据库锁似乎突然发生而没有被先前运行的任务锁定(所有这些任务在同一个单一线程下按顺序运行)。
在查看了许多其他人在数据库锁定问题方面的经验之后,我尝试在所有任务的事务完成后直接关闭数据库连接,但这并没有帮助,如果有任何事情似乎会导致更多的数据库锁定事件发生。尝试在每个任务执行之间添加一个睡眠;没有经过详尽的测试,但通常发现延迟 3 秒或以上似乎可以阻止数据库锁的出现。尝试禁用警报管理器触发的任务 - 没有任何区别。
我的印象是,我的应用程序外部的某种形式的维护任务正在定期插入并锁定数据库 - 可能会延迟写入日志。显然我不太热衷于设置任务处理延迟,所以我正在考虑设置一个数据库锁重试任务队列,以便在必要时重新尝试数据库写入;更喜欢解决,但我的想法已经不多了。
谁能想到我错过的一些原则或问题?
在 Android 和更大的 SQLite 数据库中,您偶尔会遇到数据库锁,这实际上是正常的吗?
谢谢