如何解锁SQLite数据库?

rya*_*ntm 256 sqlite

sqlite> DELETE FROM mails WHERE (`id` = 71);
SQL error: database is locked
Run Code Online (Sandbox Code Playgroud)

如何解锁数据库以便这样做?

小智 245

在Windows中,您可以尝试使用此程序http://www.nirsoft.net/utils/opened_files_view.html来查找正在处理db文件的进程.尝试关闭该程序以解锁数据库

在Linux和macOS中,您可以执行类似的操作,例如,如果您的锁定文件是development.db:

$ fuser development.db

此命令将显示锁定文件的进程:

> development.db:5430

只是杀了这个过程......

杀了-9 5430

...并且您的数据库将被解锁.

  • ......有明显的警告,你需要知道你在做什么.如果这是一个不重要的过程,那么`kill`应该没问题,但你需要小心地正确杀死它,并且`kill -9`可能是错误的和/或过度杀伤.如果进程挂起而不会死,那么有时你需要`kill -9`.但是你不想去杀掉主要的生产工作只是为了报告数据库不再被锁定! (17认同)
  • @chacham15:你假设数据库在"我的"计算机上,你忽略了许多重要进程在与锁定数据库相同的计算机上运行的可能性."更简单"的解决方案从未如此简单;) (6认同)
  • 此解决方案假定存在锁定文件的进程.进程崩溃可能会使SQLite文件处于不可用状态.在那种情况下,请参阅我的回答. (5认同)

rob*_*ert 89

我在写入过程中使应用程序崩溃导致我的sqlite数据库被锁定.这是我如何修复它:

echo ".dump" | sqlite old.db | sqlite new.db
Run Code Online (Sandbox Code Playgroud)

摘自:http://random.kakaopor.hu/how-to-repair-an-sqlite-database

  • sqlite3:`sqlite> .dump PRAGMA foreign_keys = OFF; 开始交易;/****错误:(5)数据库被锁定*****/ROLLBACK; - 由于错误 (4认同)

con*_*r42 52

SQLite wiki DatabaseIsLocked页面提供了对此错误消息的良好解释.它部分地说明争用的来源是内部的(对于发出错误的过程).

这个页面没有解释的是SQLite如何决定你的进程中的某些东西是否存在锁定以及哪些条件可能导致误报.

  • @converter42 链接已损坏。 (4认同)
  • 问题是页面不正确或过时:我有一个进程实际上什么都不做,只是一个收到锁定消息的 INSERT:这个进程不可能导致锁定。问题出在与同一个数据库交谈的另一个进程中。 (2认同)

Aar*_*ron 32

删除-journal文件听起来像一个糟糕的主意.它允许sqlite在崩溃后将数据库回滚到一致状态.如果在数据库处于不一致状态时将其删除,则会留下损坏的数据库.引用sqlite站点的页面:

如果确实发生了崩溃或断电并且磁盘上留有热日志,则原始数据库文件和热日志必须保留在磁盘上并保留其原始名称,直到另一个SQLite进程打开数据库文件并回滚.[...]

我们怀疑SQLite恢复的常见故障模式是这样的:发生电源故障.电源恢复后,善意的用户或系统管理员开始在磁盘上查看损坏情况.他们看到他们的数据库文件名为"important.data".这个文件对他们来说可能很熟悉.但在崩溃之后,还有一个名为"important.data-journal"的热门期刊.然后用户删除热门日志,认为他们正在帮助清理系统.除了用户教育之外,我们知道无法阻止这种情况.

回滚应该在下次打开数据库时自动发生,但如果进程无法锁定数据库,则会失败.正如其他人所说,其中一个可能的原因是另一个流程目前正在开放.如果数据库位于NFS卷上,则另一种可能性是过时的NFS锁定.在这种情况下,解决方法是使用未在NFS服务器上锁定的新副本替换数据库文件(mv database.db original.db; cp original.db database.db).请注意,由于NFS文件锁定的错误实现,sqlite FAQ建议谨慎对NFS卷上的数据库进行并发访问.

我无法解释为什么删除-journal文件会让你锁定以前无法访问的数据库.这是可重复的吗?

顺便说一下,-journal文件的存在并不一定意味着发生了崩溃或者有回滚的变化.Sqlite有一些不同的日志模式,在PERSIST或TRUNCATE模式下,它始终保留-journal文件,并更改内容以指示是否存在要回滚的部分事务.


小智 19

如果要删除"数据库已锁定"错误,请按照下列步骤操作:

  1. 将数据库文件复制到其他位置.
  2. 用复制的数据库替换数据库.这将取消引用正在访问数据库文件的所有进程.

  • 我如上所述尝试了'fuser <DB>',但是没有用。这个简单的步骤对我有用。 (2认同)

小智 15

如果进程锁定SQLite DB并崩溃,则数据库将永久锁定.那就是问题所在.并不是某些其他进程有锁定.

  • 那么如何解锁数据库呢? (41认同)
  • 这不是真的.锁由OS维护.阅读以下答案. (4认同)

Hea*_*ser 11

SQLite db文件只是文件,因此第一步是确保它不是只读的.另一件事是确保在数据库打开的情况下没有某种GUI SQLite DB查看器.您可以在另一个shell中打开数据库,或者您的代码可能打开了数据库.通常,如果不同的线程或SQLite数据库浏览器等应用程序打开DB进行编写,您会看到这一点.

  • 根据我的经验,SQLite数据库浏览器(SDB)可以重复锁定数据库,如果您使用它编辑数据但不将其保存在SDB中.如果你保存它,它会释放锁定. (4认同)

J.J*_*J.J 10

有些函数(例如 INDEX'ing)可能需要很长时间 - 并且它在运行时会锁定整个数据库。在这种情况下,它甚至可能不使用日志文件!

因此,检查数据库是否因进程正在主动写入而被锁定的最佳/唯一方法(因此您应该让它独自一人,直到其完成其操作)是对文件进行 md5(或某些系统上的 md5sum)两次。如果你得到一个不同的校验和,数据库正在被写入,你真的真的不想杀死 -9 该进程,因为如果你这样做,你很容易最终得到一个损坏的表/数据库。

我会重申,因为这很重要 - 解决方案不是找到锁定程序并杀死它 - 而是查找数据库是否有充分的理由具有写锁,然后从那里开始。有时,正确的解决方案就是喝杯咖啡休息一下。

创建这种锁定但未写入情况的唯一方法是,如果您的程序运行BEGIN EXCLUSIVE,因为它想要进行一些表更改或其他操作,那么无论出于何种原因,之后都不会发送END并且进程永远不会终止。在任何正确编写的代码中,满足所有这三个条件的可能性极小,因此,当有人想要杀死 -9 他们的锁定进程时,百分之九十九的情况下,锁定进程实际上是出于充分的理由锁定您的数据库。BEGIN EXCLUSIVE除非确实需要,否则程序员通常不会添加条件,因为它会阻止并发并增加用户投诉。SQLite 本身仅在真正需要时添加它(例如索引时)。

最后,正如几个答案所述,“锁定”状态并不存在于文件内部 - 它驻留在操作系统的内核中。运行的进程BEGIN EXCLUSIVE已请求操作系统对文件加锁。即使您的独占进程崩溃了,您的操作系统也将能够确定是否应该保持文件锁定!不可能出现数据库被锁定但没有进程主动锁定它的情况!当要查看哪个进程正在锁定文件时,通常最好使用 lsof 而不是 fusionr (这是一个很好的演示,说明了原因:https ://unix.stackexchange.com/questions/94316/fuser-vs-lsof-检查正在使用的文件)。或者,如果您有 DTrace (OSX),则可以在该文件上使用 iosnoop。


jog*_*pan 9

我刚才遇到了这个问题,使用存储在NFS挂载上的远程服务器上的SQLite数据库.在我使用的远程shell会话在数据库打开时崩溃后,SQLite无法获得锁定.

上面提到的恢复配方对我来说不起作用(包括首先移动然后再复制数据库的想法).但是在将其复制到非NFS系统之后,数据库变得可用,并且数据似乎没有丢失.


Zeq*_*uez 9

如果文件位于远程文件夹(例如共享文件夹)中,则可能会引发此错误。我将数据库更改为本地目录并且它运行良好。


Ben*_*n L 8

我的锁定是由系统崩溃而不是由挂起进程引起的。为了解决这个问题,我只是简单地重命名了文件,然后将其复制回其原始名称和位置。

使用Linux外壳将是...

mv mydata.db temp.db
cp temp.db mydata.db
Run Code Online (Sandbox Code Playgroud)


use*_*210 7

Pooling=true在连接字符串中添加了“ ”,它起作用了。


Kyl*_*nin 5

我发现SQLite 中锁定的各种状态的文档非常有帮助。Michael,如果您可以执行读取操作,但无法对数据库执行写入操作,则意味着某个进程已获得数据库上的 RESERVED 锁,但尚未执行写入操作。如果您使用的是 SQLite3,则有一个名为 PENDING 的新锁,其中不允许更多进程连接,但现有连接仍可以执行读取,因此如果这是问题,您应该考虑一下。