尽管使用内容提供程序和顺序数据库访问,android sqlite“数据库已锁定”错误

时间:2011-10-31 14:25:52

标签: android database sqlite android-contentprovider locked

我有一个应用(Android 2.2 Google API Level 8),它有多个活动从内容提供商提取数据(仅限SELECT数据库访问)。 它还有一个服务,中央阻塞任务队列接受任何数据库写入任务;活动可以触发服务请求(作为意图),该请求将任务放在阻塞队列上,以便由单个线程和执行进行顺序检索。数据库大约4mb。

服务使用一个数据库帮助程序来调用与数据库交互的方法,包括写入数据库;所有SQL写入都在数据库助手中执行。

  • 所有数据库写入都被事务包围。
  • 所有数据库读取都在方法结束时关闭光标。
  • 没有任何活动拥有数据库对象的句柄,他们只能通过内容提供商或服务进行通信。
  • 任何AlarmManager触发的任务(如“活动”)仅使用该服务将适当的任务弹出到队列中。
  • 该服务是唯一具有数据库帮助程序句柄的类。
  • 所有数据库写入仅通过放置在队列中的任务执行;我已经用尽地检查了任务执行顺序是否已经知道必须避免并发写入SQLite数据库。

在执行任务期间,在尝试写入由'begin transaction'的任务执行触发的数据库时,我始终遇到一个或两个“数据库被锁定”错误。

在尝试追踪锁定源时,我发现使用dbhelper.inTransaction(),dbhelper.isLockedByThisThread(),dbhelper.isLockedByOtherThread()没有帮助,因为它们不会指示意外的数据库锁定。 / p>

我发现早期检测锁的工作原理是使用beginTransaction()和setTransactionSuccessful创建一个没有任何实际SQL写代码的方法,在一个可以记录问题的try catch块中 - 总是由beginTransaction()触发。

我把这个数据库锁定陷阱放在每个阻塞队列任务方法的任何一侧,期望/希望我找到一个单一的罪魁祸首,在完成后将数据库保持在锁定状态。 我找不到一致的罪魁祸首。在从任务调用开始向下钻取到数据库写入之后,我发现数据库锁可能看起来很突然而没有被先前运行的任务锁定(所有这些任务在相同的单一线程下按顺序运行)。

在查看了许多其他人对数据库锁定问题的经验之后,我已经尝试在事务完成所有任务后直接关闭数据库连接但这没有帮助,如果有什么似乎有更多的数据库锁定事件发生。尝试在每个任务执行之间添加睡眠;没有详尽的测试,但一般发现延迟3秒或以上似乎停止出现数据库锁。尝试禁用警报管理器解雇的任务 - 没有任何区别。

我的印象是我的应用程序外部的某种形式的维护任务正在进入并定期锁定数据库 - 可能会延迟写入日志。显然,我不太热衷于设置任务处理延迟,因此我正在考虑使用数据库锁重试任务队列来根据需要重新尝试数据库写入;更愿意解决,但我的想法已经不多了。

任何人都可以想到我错过了一些原则或陷阱吗?

在Android和更大的SQLite数据库中,您是否会偶尔获得数据库锁定?

由于

3 个答案:

答案 0 :(得分:7)

只要您使用单个数据库连接,SQLite就可以保证从多个线程进行顺序访问。您打开和关闭数据库连接的方式和位置是什么?

我通常建议在启动时打开数据库一次,不要关闭它。关闭没有任何好处,因为SQLite的事务性质意味着无论如何都会尽快将写入刷新到持久存储。

答案 1 :(得分:0)

我会检查一些调用数据库或调用调用数据库的其他活动的活动是否只有一个实例。在某种意义上,它可以锁定自己。

答案 2 :(得分:0)

关于

  

在Android和更大的SQLite数据库中,您是否会偶尔获得数据库锁定?

不,偶尔进行数据库锁定绝对不正常。通过阅读您的故事,您说您从数据库中提取服务和内容提供商,因此您可能会在两次访问之间锁定数据库。

我通常做的是确保通过内容提供商处理所有数据库访问。通过为数据库提供单一入口点,您可以确保每个软件组件使用相同的逻辑来访问数据库。是否可以让您的服务通过内容提供商访问数据库?

记住,通过将数据库置于内容提供程序后面,它仍然可以被多个线程同时访问。为了确保您一次只访问一个数据库,您可以在内容提供程序内部的数据库上放置同步构造。显然,如果你对数据库做了很多长时间的写入/读取,以这种方式锁定将绝对会破坏你的应用程序。将所有数据库代码放在内容提供程序中也将为您提供单点调试,这将帮助您确定多个线程是否正在访问数据库。