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

如何解锁数据库,这样才能正常工作?

4

38 回答 38

300

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

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

$定影器开发.db

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

> 开发.db:5430

直接杀掉进程...

杀死-9 5430

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

于 2010-08-13T22:37:16.860 回答
95

我在写入期间通过崩溃应用程序导致我的 sqlite 数据库被锁定。这是我修复它的方法:

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

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

于 2011-10-12T13:12:52.397 回答
55

SQLite wiki DatabaseIsLocked页面提供了此错误消息的解释。它部分说明争用的来源是内部的(对于发出错误的进程而言)。本页未解释的是 SQLite 如何确定您的进程中的某些内容持有锁定以及哪些条件可能导致误报。

当您尝试从同一数据库连接同时对数据库执行两项不兼容的操作时,会出现此错误代码。


v3 中引入的与文件锁定相关的更改,可能对未来的读者有用,可以在这里找到:SQLite 版本 3 中的文件锁定和并发

于 2008-10-20T14:24:02.277 回答
33

删除 -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 文件,并更改内容以指示是否有部分事务要回滚。

于 2009-06-22T14:25:15.060 回答
30

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

  1. 将您的数据库文件复制到其他位置。
  2. 用复制的数据库替换数据库。这将取消引用正在访问您的数据库文件的所有进程。
于 2013-03-07T12:28:33.807 回答
15

如果进程在 SQLite DB 上锁定并崩溃,则 DB 将永久保持锁定状态。那就是问题所在。这并不是说其他​​一些进程有锁。

于 2009-01-29T22:58:06.557 回答
13

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

于 2008-09-29T22:39:14.273 回答
12

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

使用 linux shell 会...

mv mydata.db temp.db
cp temp.db mydata.db
于 2009-08-04T11:02:36.647 回答
11

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

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

于 2011-06-16T03:19:32.503 回答
7

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

于 2016-03-08T09:49:00.987 回答
4

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

于 2008-11-14T18:44:35.950 回答
4

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

于 2012-09-12T20:29:35.770 回答
4

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

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

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

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

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

于 2015-02-19T16:05:22.777 回答
3

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

不要忘记致电:

sqlite_reset(xxx);

或者

sqlite_finalize(xxx);
于 2012-02-17T18:39:06.070 回答
2

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

但是,如果能够找到根本原因,那就太好了。

于 2008-11-14T18:37:13.000 回答
2

应该是数据库的内部问题......
对我来说,它已经在尝试使用“SQLite manager”浏览数据库后表现出来......
所以,如果你找不到另一个进程连接到数据库并且你无法修复它,试试这个激进的解决方案:

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

我的 Linux 环境中的lsof命令帮助我找出一个进程正在挂起以保持文件打开。
杀掉进程,问题就解决了。

于 2011-09-16T20:29:25.050 回答
2

这个链接解决了这个问题。:当 Sqlite 给出: 数据库锁定错误 它解决了我的问题可能对你有用。

并且您可以使用开始事务和结束事务来避免将来锁定数据库。

于 2013-05-16T05:50:51.957 回答
1

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

于 2009-06-12T20:20:21.627 回答
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 程序。

于 2010-06-21T10:45:32.213 回答
1

我只是有同样的错误。在 5 个矿井谷歌搜索后,我发现我没有关闭一个正在使用数据库的 shell 女巫。只需将其关闭并重试;)

于 2011-12-15T09:11:05.793 回答
1

我有同样的问题。显然,回滚功能似乎用与 db 文件相同但没有最新更改的日志覆盖 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 )
于 2012-02-17T11:56:43.823 回答
1

出现此异常的一个常见原因是当您尝试执行写入操作同时仍为读取操作保留资源时。例如,如果您从表中选择,然后尝试更新您选择的内容,而不先关闭您的 ResultSet。

于 2012-10-24T17:33:42.863 回答
1

我在多线程应用程序中也遇到了“数据库被锁定”错误,这似乎是SQLITE_BUSY结果代码,我通过将sqlite3_busy_timeout设置为合适的长度(如 30000)来解决它。

(顺便说一句,在一个 7 岁的问题上没有人发现这一点真是太奇怪了!SQLite 真的是一个奇特而令人惊叹的项目......)

于 2016-03-02T22:38:09.657 回答
1

一个老问题,有很多答案,这是我最近阅读上述答案所遵循的步骤,但在我的情况下,问题是由于 cifs 资源共享造成的。这个案例以前没有报道过,所以希望它对某人有所帮助。

  • 检查您的 java 代码中没有打开任何连接。
  • 检查没有其他进程正在使用带有 lsof 的 SQLite db 文件。
  • 检查正在运行的 jvm 进程的用户所有者对该文件是否具有 r/w 权限。
  • 尝试在连接打开时强制锁定模式

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

如果您在 NFS 共享文件夹上使用 SQLite db 文件,请检查SQLite 常见问题的这一点,并查看安装配置选项以确保避免锁定,如下所述

//myserver /mymount cifs username=*****,password=*****,iocharset=utf8,sec=ntlm,file,nolock,file_mode=0700,dir_mode=0700,uid=0500,gid=0500 0 0
于 2016-04-20T10:31:15.213 回答
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 用于 172.22.84.87 的 SM_MON

空间情况处理完毕后,一切都恢复了正常。

于 2016-08-09T03:21:29.980 回答
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
于 2018-02-25T20:51:54.863 回答
1

根据我的经验,此错误是由以下原因引起的:您打开了多个连接。

例如:

  1. 1 个或多个 sqlitebrowser (GUI)
  2. 1 个或多个电子线
  3. 导轨螺纹

我不确定 SQLITE3 如何处理多线程/请求的细节,但是当我关闭 sqlitebrowser 和电子线程时,rails 运行良好,不会再阻塞。

于 2021-04-18T09:19:24.507 回答
0

根据您之前的评论,您说存在 -journal 文件。

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

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

于 2008-12-29T01:44:57.637 回答
0

正如 Seun Osewa 所说,有时僵尸进程会坐在终端中并获得锁,即使您认为这是不可能的。您的脚本运行,崩溃,然后您返回到提示符,但是库调用在某处产生了一个僵尸进程,并且该进程具有锁定。

关闭您所在的终端(在 OSX 上)可能会起作用。重新启动将起作用。您可以寻找没有做任何事情的“python”进程(例如),然后杀死它们。

于 2010-01-07T05:51:56.330 回答
0

你可以试试这个:.timeout 100设置 timeout 。我不知道在命令行中发生了什么,但在 C# .Net 中执行此操作时:"UPDATE table-name SET column-name = value;"我得到数据库已锁定,但这"UPDATE table-name SET column-name = value"一切正常。

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

于 2010-06-27T11:28:28.007 回答
0

将 Delphi 与 LiteDAC 组件一起使用时出现此错误。事实证明,如果 SQLite 连接组件(在本例中为 TLiteConnection)的 Connected 属性设置为 True,则只有在从 Delphi IDE 运行我的应用程序时才会发生这种情况。

于 2014-03-14T20:32:55.797 回答
0

由于某种原因,数据库被锁定。这是我修复它的方法。

  1. 我将 sqlite 文件下载到我的系统(FTP)
  2. 删除了网上的sqlite文件
  3. 将文件上传回托管服务提供商

它现在工作正常。

于 2014-05-24T14:12:47.283 回答
0

就我而言,我也遇到了这个错误。

我已经检查了可能导致数据库锁定的其他进程,例如(SQLite 管理器,连接到我的数据库的其他程序)。但是没有其他程序可以连接到它,它只是同一个应用程序中的另一个活动SQLConnection保持连接

在建立新的 SQLConnection新的命令之前,请尝试检查您之前可能仍处于连接状态的活动 SQLConnection (先断开连接) 。

于 2016-04-22T17:54:05.780 回答
0

这是因为该数据库上正在运行一些其他查询。SQLite 是一个查询同步执行的数据库。因此,如果其他人正在使用该数据库,那么如果您执行查询或事务,则会出现此错误。

因此,停止使用特定数据库的进程,然后执行您的查询。

于 2016-05-30T08:30:30.810 回答
0

我在尝试写入数据时构建的 C# .NET 4.6.1 应用程序中也收到了 sqlite 锁,但在我的开发机器上的 Visual Studio 中运行该应用程序时没有。相反,只有在远程 Windows 10 机器上安装并运行应用程序时才会发生这种情况。

最初我以为是文件系统权限,但结果是我使用 Nuget 在项目中安装的 System.Data.SQLite 包驱动程序(v1.0.109.2)导致了问题。我删除了 NuGet 包,并在项目中手动引用了旧版本的驱动程序,一旦在远程计算机上重新安装了应用程序,锁定问题就神奇地消失了。只能认为最新的驱动程序或 Nuget 包存在错误。

于 2018-12-13T10:58:40.220 回答
0

我运行了“DB Browser for SQLite”工具,并且也在其中工作。显然,该工具也会锁定事物。点击“Write Changes”或“Revert Changes”后,锁定消失了,其他进程(A React-Native 脚本)不再给出该错误。

SQLite 数据库浏览器 - 写入更改

于 2020-11-06T14:34:51.400 回答
0

我在 Google Chrome 中查看存储的密码时遇到了这个错误。

# ~/.config/google-chrome/Default
$ sqlite3 Login\ Data
SQLite version 3.35.5 2021-04-19 18:32:05
sqlite> .tables
Error: database is locked

如果您不特别关心父进程,或者您不想停止正在使用数据库的当前 chrome 进程,只需将文件复制到其他位置即可。

$ cp Login\ Data ~/tmp/ld.sql
$ sqlite3 ~/tmp/ld.sql .tables
field_info              meta   sync_model_metadata   
insecure_credentials    stats                 
logins                  sync_entities_metadata

这样做将允许您在不干扰或停止主 chrome 进程的情况下读取数据库的内容。

于 2021-10-02T19:51:06.827 回答