如何解锁SQLite数据库?


269
sqlite> DELETE FROM mails WHERE (`id` = 71);
SQL error: database is locked

我该如何解锁数据库才能正常工作?


可能还有另一个进程正在访问数据库文件-您是否检查了lsof?
存在的

我遇到了同样的问题,当我将其停用,我的应用程序运行正常时,问题出在防病毒中,但是当我将其激活时,我发现一些错误“数据库已锁定”,希望对您有所帮助。
user8510915

Answers:


267

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

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

$热熔器development.db

此命令将显示什么进程正在锁定文件:

> development.db:5430

只是杀死进程...

杀死-9 5430

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


19
...显然需要您知道自己在做什么。如果这不是很重要的过程,那kill应该没问题,但是您需要小心地杀死它,这kill -9可能是错误的和/或过大的杀伤力。如果该进程已挂起并且不会以其他方式终止,那么有时您确实需要kill -9。但是,您不想去干掉主要的生产工作,而是可以报告数据库已不再锁定!
2011年

比较简单的解决方案是重新启动计算机。
chacham15 2012年

7
@ chacham15:您假设数据库位于“我的”计算机上,而忽略了许多重要进程与数据库锁定的计算机在同一台计算机上运行的可能性。“更简单”的解决方案从未如此简单;)
tzot

1
@KyleCarlson-sqlite和mysql在这方面根本不同。SQLite-db-browser没有什么特别的错误。
Berry Tsakala

6
该解决方案假定存在一个锁定文件的进程。进程崩溃可能会使SQLite文件处于不可用状态。在这种情况下,请参阅我的答案。
罗伯特2014年

90

我通过写操作导致应用崩溃导致我的sqlite数据库被锁定。这是我固定的方法:

echo ".dump" | sqlite old.db | sqlite new.db

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


4
sqlite3:sqlite> .dump PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; /**** ERROR: (5) database is locked *****/ ROLLBACK; -- due to errors
woky

不适用于FOREIGN KEY constraint failed (RELEASE RESTOREPOINT)
gies0r

52

下面列出的DatabaseIsLocked页面不再可用。“文件锁定和并发”页面描述了与v3中引入的文件锁定有关的更改,可能对以后的读者有用。https://www.sqlite.org/lockingv3.html

SQLite Wiki DatabaseIsLocked页面对此错误消息提供了很好的解释。它部分说明争用的源是内部的(对于发出错误的过程而言)。

该页面没有解释的是SQLite如何确定您的进程中的某些内容已锁定,以及哪些条件可能导致误报。


2
问题是页面不正确或已过期:我有一个进程实际上只执行一个INSERT来获取该锁定消息,而实际上什么也没做:该进程不可能引起锁定。问题出在与同一个数据库对话的另一个过程中。
丹·詹姆森

4
@ converter42链接断开。
Ole Tange

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常见问题解答建议您谨慎访问NFS卷上的数据库。

我无法解释为什么删除-journal文件会使您锁定以前无法访问的数据库。那是可复制的吗?

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


23

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

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

2
我如上所述尝试了'fuser <DB>',但是没有用。这个简单的步骤对我有用。
成龙2015年

就我而言,我还必须重新启动Jupyter Notebook。
维克多

15

如果进程在SQLite数据库上具有锁定并崩溃,则该数据库将永久保持锁定状态。那就是问题所在。并非其他进程具有锁定。


48
那么如何解锁数据库?
埃里克·卡普伦

4
事实并非如此。锁由操作系统维护。阅读下面的答案。
JJ

13

SQLite db文件只是文件,因此第一步是确保它不是只读的。要做的另一件事是确保在打开数据库时没有某种GUI SQLite DB查看器。您可以在另一个外壳中打开数据库,或者您的代码可以打开数据库。通常,如果其他线程或应用程序(例如SQLite数据库浏览器)打开了可写的数据库,就会看到此消息。


4
以我的经验,SQLite数据库浏览器(SDB)可重复地锁定数据库,前提是您用它编辑数据,但是没有将其保存在SDB中。如果您保存它,它将释放锁定。
Chelonian

我可以插入,但不能删除。
温妮

10

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

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


9

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

使用Linux shell将是...

mv mydata.db temp.db
cp temp.db mydata.db

非常简单的解决方案,解决了网络驱动器上数据库锁定的问题。
Maverick2805

7

Pooling=true在连接字符串中添加了“ ”,它可以正常工作。


4

我发现有关SQLite锁定的各种状态的文档非常有用。迈克尔,如果您可以执行读取操作但不能执行对数据库的写入操作,则意味着进程已在数据库上获得了RESERVED锁,但尚未执行写入操作。如果您使用的是SQLite3,则有一个名为PENDING的新锁,该锁不允许再有更多的进程连接,但是现有的连接会阻止执行读取操作,因此,如果这是问题,您应该考虑一下。


4

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


3

我在应用程序中遇到了此类问题,该问题可通过2个连接访问SQLite-一个是只读的,第二个用于读写。看起来该只读连接阻止了第二连接的写入。最后,事实证明,使用后需要立即完成或至少重置准备好的语句。直到打开准备好的语句,它才导致数据库被阻止写入。

不要忘记打电话:

sqlite_reset(xxx);

要么

sqlite_finalize(xxx);

3

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

因此,最好的/唯一的检查数据库是否已锁定的最佳方法是因为某个进程正在主动向其写入数据(因此,在完成其操作之前,您应将其搁置一旁)是对文件md5(或某些系统上的md5sum)进行两次。如果您获得不同的校验和,则说明数据库正在写入中,并且您真的真的不想终止-9这个过程,因为这样做很容易导致损坏的表/数据库。

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

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

最后,正如几个答案所述,在文件内部不存在“锁定”状态-它位于操作系统的内核中。其运行进程BEGIN EXCLUSIVE已经从OS请求的锁被放置在该文件。即使您的独占进程崩溃了,您的操作系统也可以弄清楚它是否应该保持文件锁定!最终无法获得已锁定的数据库,但是没有进程正在主动锁定它!当要查看哪个进程正在锁定文件时,通常最好使用lsof而不是fuser(这很好地说明了原因:https : //unix.stackexchange.com/questions/94316/fuser-vs-lsof-查看使用中的文件)。或者,如果您有DTrace(OSX),则可以在文件上使用iosnoop。


2

我只是发生了类似的事情-我的Web应用程序能够从数据库中读取,但是无法执行任何插入或更新。重新启动Apache至少可以暂时解决该问题。

但是,能够找到根本原因会很不错。


2

我的Linux环境上的lsof命令帮助我弄清楚了一个进程正在挂起,使文件保持打开状态。
杀死进程并解决问题。



2

应该是数据库的内部问题...
对我来说,它是在尝试使用“ SQLite管理器”浏览数据库后才表现出来的...
因此,如果找不到另一个连接到数据库的进程并且只是无法修复它,只需尝试以下根本解决方案:

  1. 提供导出表的信息(可以在Firefox上使用“ SQLite管理器”)
  2. 如果迁移更改了数据库方案,请删除上一次失败的迁移
  3. 重命名您的“ database.sqlite”文件
  4. 执行“ rake db:migrate”以创建新的工作数据库
  5. 提供对数据库进行表导入的正确权限
  6. 导入备份表
  7. 编写新的迁移
  8. 用“ rake db:migrate” 执行

1

我在从终端会话运行Python脚本的Mac OS X 10.5.7上遇到了同样的问题。即使我已停止脚本并且终端窗口位于命令提示符下,它在下次运行时也会出现此错误。解决方案是关闭终端窗口,然后再次打开它。对我来说没有意义,但确实有效。


1

我只是有同样的错误。经过五分钟的谷歌搜索后,我发现我没有关闭一个正在使用数据库的贝壳巫婆。只需关闭它,然后再试一次;)


1

我有同样的问题。显然,回滚功能似乎用与日志文件相同的日志覆盖了db文件,但是没有最新的更改。我已经在下面的代码中实现了它,此后一直运行良好,而在此之前,由于数据库保持锁定状态,我的代码只会陷入循环。

希望这可以帮助

我的python代码

##############
#### Defs ####
##############
def conn_exec( connection , cursor , cmd_str ):
    done        = False
    try_count   = 0.0
    while not done:
        try:
            cursor.execute( cmd_str )
            done = True
        except sqlite.IntegrityError:
            # Ignore this error because it means the item already exists in the database
            done = True
        except Exception, error:
            if try_count%60.0 == 0.0:       # print error every minute
                print "\t" , "Error executing command" , cmd_str
                print "Message:" , error

            if try_count%120.0 == 0.0:      # if waited for 2 miutes, roll back
                print "Forcing Unlock"
                connection.rollback()

            time.sleep(0.05)    
            try_count += 0.05


def conn_comit( connection ):
    done        = False
    try_count   = 0.0
    while not done:
        try:
            connection.commit()
            done = True
        except sqlite.IntegrityError:
            # Ignore this error because it means the item already exists in the database
            done = True
        except Exception, error:
            if try_count%60.0 == 0.0:       # print error every minute
                print "\t" , "Error executing command" , cmd_str
                print "Message:" , error

            if try_count%120.0 == 0.0:      # if waited for 2 miutes, roll back
                print "Forcing Unlock"
                connection.rollback()

            time.sleep(0.05)    
            try_count += 0.05       




##################
#### Run Code ####
##################
connection = sqlite.connect( db_path )
cursor = connection.cursor()
# Create tables if database does not exist
conn_exec( connection , cursor , '''CREATE TABLE IF NOT EXISTS fix (path TEXT PRIMARY KEY);''')
conn_exec( connection , cursor , '''CREATE TABLE IF NOT EXISTS tx (path TEXT PRIMARY KEY);''')
conn_exec( connection , cursor , '''CREATE TABLE IF NOT EXISTS completed (fix DATE, tx DATE);''')
conn_comit( connection )

1

发生此异常的一个常见原因是,当您尝试执行写操作时仍保留用于读操作的资源。例如,如果您从表中进行选择,然后尝试更新选择的内容,而无需先关闭ResultSet。


1

我也在多线程应用程序中也遇到“数据库已锁定”错误,这似乎是SQLITE_BUSY结果代码,我通过设置sqlite3_busy_timeout解决了为适当的长于30000的方法来。

(附带说明,在一个7年的历史上,没有人发现这个问题是多么奇怪!SQLite确实是一个奇特而神奇的项目...)


1

在关闭重新启动选项之前,值得一看的是,您是否可以找到sqlite数据库的用户。

在Linux上,可以fuser为此目的使用:

$ fuser database.db

$ fuser database.db-journal

就我而言,我得到以下回应:

philip    3556  4700  0 10:24 pts/3    00:00:01 /usr/bin/python manage.py shell

这表明我有另一个使用数据库的pid 3556(manage.py)的Python程序。


1

一个古老的问题,有很多答案,这是我最近在阅读上面的答案时遵循的步骤,但就我而言,问题是由于cifs资源共享造成的。以前没有此案例的报道,因此希望对您有所帮助。

  • 检查您的Java代码中是否没有打开的连接。
  • 检查是否其他进程正在将您的SQLite数据库文件与lsof一起使用。
  • 检查正在运行的jvm进程的用户所有者是否对该文件具有读/写权限。
  • 尝试通过以下方式在连接开口上强制使用锁定模式:

    final SQLiteConfig config = new SQLiteConfig();
    
    config.setReadOnly(false);
    
    config.setLockingMode(LockingMode.NORMAL);
    
    connection = DriverManager.getConnection(url, config.toProperties());

如果您使用过NFS共享文件夹的SQLite数据库文件,检查了这一点 SQLite的常见问题,并检查您的安装配置选项,以确保您避免了锁,描述在这里

//myserver /mymount cifs username=*****,password=*****,iocharset=utf8,sec=ntlm,file,nolock,file_mode=0700,dir_mode=0700,uid=0500,gid=0500 0 0

1

我在与此处描述的情况有些不同的情况下遇到此错误。

SQLite数据库位于3个服务器共享的NFS文件系统上。在其中两台服务器上,我能够在数据库上成功运行查询,而在第三台服务器上,我则收到了“数据库已锁定”消息。

这第三台机器的问题是它没有剩余空间了/var。每当我尝试在此文件系统中的任何SQLite数据库中运行查询时,都会收到“数据库已锁定”消息,并且在日志中也出现此错误:

8月8日10:33:38 server01内核:锁定:无法监视172.22.84.87

而且这个还:

8月8日10:33:38 server01 rpc.statd [7430]:无法插入:写入/var/lib/nfs/statd/sm/other.server.name.com:设备8月8日10:33没有剩余空间: 38 server01 rpc.statd [7430]:STAT_FAIL到server01的SM_MON为172.22.84.87

处理好空间情况后,一切恢复正常。


1

如果您尝试解锁Chrome数据库使用SQLite查看它,则只需关闭Chrome。

视窗

%userprofile%\Local Settings\Application Data\Google\Chrome\User Data\Default\Web Data

or

%userprofile%\Local Settings\Application Data\Google\Chrome\User Data\Default\Chrome Web Data

苹果电脑

~/Library/Application Support/Google/Chrome/Default/Web Data

0

从先前的评论中,您说到存在-journal文件。

这可能意味着您已经打开和(独占?)事务并且尚未提交数据。您的程序或其他进程是否没有将-journal留下?

重新启动sqlite进程将查看日志文件并清理所有未提交的操作并删除-journal文件。


0

正如Sese Osewa所说,有时候僵尸进程会在终端中坐上锁,即使您认为不可能,也需要锁。您的脚本运行,崩溃,然后返回到提示符,但库调用在某个地方生成了一个僵尸进程,并且该进程具有锁定。

关闭您所在的终端(在OSX上)可能会起作用。重新启动将起作用。您可能会寻找不做任何事情的“ python”进程(例如)并将其杀死。


0

您可以尝试以下方法:.timeout 100设置超时时间。我不知道在命令行中会发生什么,但是在C#.Net中执行此操作时:"UPDATE table-name SET column-name = value;"我得到数据库已锁定,但这"UPDATE table-name SET column-name = value"正常。

看起来,当您添加;时,sqlite's将寻找进一步的命令。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.