安卓数据库锁定

45

我遇到了以下错误,请问如何解锁我的数据库?

10-28 08:43:26.510: ERROR/AndroidRuntime(881): FATAL EXCEPTION: Thread-11
10-28 08:43:26.510: ERROR/AndroidRuntime(881): android.database.sqlite.SQLiteDatabaseLockedException: database is locked
10-28 08:43:26.510: ERROR/AndroidRuntime(881):     at android.database.sqlite.SQLiteDatabase.dbopen(Native Method)
10-28 08:43:26.510: ERROR/AndroidRuntime(881):     at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:983)
10-28 08:43:26.510: ERROR/AndroidRuntime(881):     at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:956)
10-28 08:43:26.510: ERROR/AndroidRuntime(881):     at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:1021)
10-28 08:43:26.510: ERROR/AndroidRuntime(881):     at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:742)
10-28 08:43:26.510: ERROR/AndroidRuntime(881):     at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:221)
10-28 08:43:26.510: ERROR/AndroidRuntime(881):     at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:149)
10-28 08:43:26.510: ERROR/AndroidRuntime(881):     at com.aa.me.vianet.dbAdapter.DbAdapter.open(DbAdapter.java:25)
10-28 08:43:26.510: ERROR/AndroidRuntime(881):     at com.aa.me.vianet.services.NotificationManagerThread.run(NotificationManagerThread.java:49)

1
  1. 确保在同一文件上只使用一个SQLiteOpenHelper。
  2. 确保每次只有一个线程在使用您的SQLiteDatabase。
- Jens
8个回答

50

我认为您可能忘记关闭数据库,或者在您尝试写入数据库时,另一个线程正在向数据库中写入数据。当SQLite尝试写入数据库时,会对其进行锁定,以避免其他实体尝试同时写入同一数据库而导致的损坏。Android仅会在日志窗口中显示错误,您提供的查询将被忽略。

因此,我建议:

  • 只从一个SQLOpenHelper访问数据库
  • 确保在使用完后关闭所有数据库帮助程序的实例
  • 确保始终使用endTransaction() 结束事务,即使您没有设置它们成功(即如果您想回滚它们),如果您使用事务,请注意这一点
  • 您可以尝试使用OrmLite,我没有使用过它,但我听说其他人在这里大加赞扬。

10
我曾为 Android 写下 OrmLite 的原始端口。你的第一个建议是只使用一个帮助程序,这是个好建议。但你的第二个建议与第一个相矛盾。“关闭所有数据库帮助程序的实例”意味着不止一个。一定要只用一个!并且,你无需关闭帮助程序的连接,请参见我的回答。我最初编写了复杂的引用计数代码来帮助 OrmLite 保持一个帮助程序存活,并在完成后关闭它,但事实证明,SQLite "连接"只是文件句柄。系统将在转储进程时为您关闭它们。 - Kevin Galligan
嘿,凯文,这是否意味着你永远不必关闭数据库处理程序? - Todd Davies
2
是的,我知道这听起来很糟糕。处理程序只是一个文件句柄。它将在进程死亡时关闭。SQLite不会自己损坏。至于仅在logcat中显示错误,这对于“插入”是正确的,但不适用于其他方法。这就是为什么您应该始终调用“insertOrThrow”的原因。 - Kevin Galligan
有没有关于这个的好教程?我从来没有看到过一份全面的SQLite在Android上的教程 :-( 谢谢 :D - Todd Davies
6
是的,请查看我在此处的回答:https://dev59.com/6XE95IYBdhLWcg3wCJNf#3689883 它链接到各种最佳实践示例。 - Kevin Galligan
如果我想备份我的数据库 - 并且备份会锁定数据库 - 那么,我是否被迫关闭我的帮助程序,或者它仍然可以开着,只是在备份期间不写入它? - JohnyTex

15

你能修复这个链接吗?如何处理单连接的多线程访问? - Michael
我使用了这种方法,但在我的情况下不起作用,请看一下我的问题链接在这里... - MobileEvangelist
你正在使用一些表现奇怪的外部API。我猜测你需要调整你调用它们的方式。UrbanAirship不太可能经常出现这种崩溃。 - Kevin Galligan

8
这是发生的原因是因为您一次只能打开一个到数据库的连接(这是为了防止在修改数据库时出现竞争条件)。我猜您从不同的线程多次连接到数据库?最简单的解决方法是为您的数据库创建一个ContentProvider前端。这将能够处理来自多个线程的查询。
要了解更多信息,请查看此blogpost

博客文章的链接已经失效,新链接为http://www.touchlab.co/blog/android-sqlite-locking/。 - pengwang
它以前不行,"新链接"也是如此,但现在博客文章似乎可以工作了,尽管"新链接"仍然无法使用。 - christophercotton
我在多进程应用程序中使用数据库,只有少数用户遇到了这个问题。请问您能告诉我解决方法吗?数据库被锁定(代码5):在编译PRAGMA日志模式时。 - Mateen Chaudhry

7
我也遇到了同样的问题,尝试使用这个。
   db.beginTransactionNonExclusive();
   try {
       //do some insertions or whatever you need
       db.setTransactionSuccessful();
   } finally {
       db.endTransaction();
   }

我尝试使用db.beginTransaction,但它锁定了数据库。


0

我曾经遇到过同样的问题,当我尝试通过ContentResolver访问我的数据库时,我已经有一个直接的SQLiteDatabase连接打开了(需要用于事务)。

我通过改变代码顺序来解决这个问题,所以ContentResolver的内容在我直接打开SQLiteDatabase连接之前完成。

我还删除了一些代码,因此不再关闭我的直接SQLiteDatabase

阅读this answer是值得的,因为它提供了许多其他有用的指导。


0

我曾经遇到过类似的错误。我的问题是,我不小心给了两个辅助类相同的数据库名称,因此它们最终同时访问了同一个数据库。所以请确保您不要使用多个辅助类访问单个数据库。


0

当我们遇到以下错误时,我们可以做什么。

android.database.sqlite.SQLiteDatabaseLockedException: database is locked

数据库锁定意味着数据库正在执行某些其他线程的任务,同时,其他线程在执行该任务时发生了这种情况。

因此,在我的情况下解决方案是:

在执行查询或在数据库中进行事务之前,您必须像这样检查。

if(!sqLiteDatabase.isDbLockedByCurrentThread() && !sqLiteDatabase.isDbLockedByOtherThreads()) 

0
在我的情况下,这个错误是由于常见的错误导致的。最初,我的SQLite数据库是通过从MySQL接收的JsonArray数据填充的。在我添加了SQLite数据库中的附加列之后,类似的错误发生了。简单地说,我忘记在MySQL数据库中添加相应的列.. :)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接