【问题标题】:How do I unlock a SQLite database?如何解锁 SQLite 数据库?
【发布时间】:2010-09-14 03:24:00
【问题描述】:
sqlite> DELETE FROM mails WHERE (`id` = 71);
SQL error: database is locked

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

【问题讨论】:

  • 可能有另一个进程正在访问数据库文件 - 你检查 lsof 了吗?
  • 我遇到了同样的问题,问题出在杀毒软件中,当我停用它时,我的应用程序运行良好,但是当我激活它时,我发现一些错误“数据库已锁定”,我希望这会有所帮助你。

标签: sqlite


【解决方案1】:

在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。但是您不想为了报告数据库不再锁定而杀死主要生产作业!
  • 更简单的解决方案是重新启动计算机。
  • @chacham15:您假设数据库在“我的”计算机上,并且您忽略了许多重要进程与锁定数据库的计算机在同一台计算机上运行的可能性。 “更简单”的解决方案从未如此简单;)
  • @KyleCarlson - sqlite 和 mysql 在这方面根本不同。 SQLite-db-browser 没有什么特别的问题。
  • 此解决方案假定存在锁定文件的进程。一个进程可能会崩溃,导致 SQLite 文件处于不可用状态。在这种情况下,请参阅我的答案。
【解决方案2】:

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

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

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

【讨论】:

  • sqlite3: sqlite> .dump PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; /**** ERROR: (5) database is locked *****/ ROLLBACK; -- due to errors
  • 不适用于FOREIGN KEY constraint failed (RELEASE RESTOREPOINT)
【解决方案3】:

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

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


与 v3 中引入的文件锁定相关的更改可能对未来的读者有用,可以在这里找到:File Locking And Concurrency In SQLite Version 3

【讨论】:

  • 问题是页面不正确或过时:我有一个进程实际上什么都不做,只是一个 INSERT 正在获取该锁定消息:这个进程不可能有导致锁定。问题出在与同一个数据库通信的另一个进程中。
  • @converter42 链接断开。
【解决方案4】:

删除 -journal 文件听起来是个糟糕的主意。它允许 sqlite 在崩溃后将数据库回滚到一致的状态。如果您在数据库处于不一致状态时删除它,那么您将留下一个损坏的数据库。引用来自sqlite site的页面:

如果确实发生崩溃或断电并且热日志留在磁盘上,则原始数据库文件和热日志必须以其原始名称保留在磁盘上,直到数据库文件被另一个 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 文件,并更改内容以指示是否有部分事务要回滚。

【讨论】:

    【解决方案5】:

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

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

    【讨论】:

    • 我试过上面描述的'fuser ',但是没有用。这个简单的步骤对我有用。
    • 就我而言,我还必须重新启动我的 Jupyter Notebook。
    【解决方案6】:

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

    【讨论】:

    • 这不是真的。锁由操作系统维护。阅读下面的答案。
    【解决方案7】:

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

    【讨论】:

    • 根据我的经验,如果您使用 SQLite 数据库浏览器 (SDB) 编辑数据但不将其保存在 SDB 中,它会重复锁定数据库。如果你保存它,它会释放锁。
    • 可以插入但不能删除。
    【解决方案8】:

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

    使用 linux shell 会...

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

    【讨论】:

    • 非常简单的解决方案,解决了我在网络驱动器上锁定数据库的问题。
    【解决方案9】:

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

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

    【讨论】:

      【解决方案10】:

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

      【讨论】:

        【解决方案11】:

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

        【讨论】:

          【解决方案12】:

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

          【讨论】:

            【解决方案13】:

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

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

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

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

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

            【讨论】:

              【解决方案14】:

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

              别忘了打电话:

              sqlite_reset(xxx);
              

              或

              sqlite_finalize(xxx);
              

              【讨论】:

                【解决方案15】:

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

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

                【讨论】:

                  【解决方案16】:

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

                  【讨论】:

                    【解决方案17】:

                    这个链接解决了问题。 :When Sqlite gives : Database locked error 它解决了我的问题可能对你有用。

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

                    【讨论】:

                      【解决方案18】:

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

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

                      【讨论】:

                        【解决方案19】:

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

                        【讨论】:

                          【解决方案20】:

                          我刚刚遇到了同样的错误。 在 5 次 minets google-ing 之后,我发现我没有关闭一个正在使用 db 的 shell 女巫。 只需关闭它并重试;)

                          【讨论】:

                            【解决方案21】:

                            我遇到了同样的问题。显然,回滚功能似乎用与 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 )
                            

                            【讨论】:

                              【解决方案22】:

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

                              【讨论】:

                                【解决方案23】:

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

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

                                【讨论】:

                                【解决方案24】:

                                在关闭重启选项之前,有必要看看是否可以找到 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 程序。

                                【讨论】:

                                  【解决方案25】:

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

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

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

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

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

                                  【讨论】:

                                    【解决方案26】:

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

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

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

                                    8 月 8 日 10:33:38 server01 kernel: lockd: cannot monitor 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

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

                                    【讨论】:

                                      【解决方案27】:

                                      如果您尝试将 Chrome 数据库解锁为 view it with 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
                                      

                                      【讨论】:

                                        【解决方案28】:

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

                                        例如:

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

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

                                        【讨论】:

                                          【解决方案29】:

                                          从您之前的 cmets 中,您说存在一个 -journal 文件。

                                          这可能意味着您已经打开和(独家?)交易,但尚未提交数据。您的程序或其他进程是否留下了 -journal?

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

                                          【讨论】:

                                            【解决方案30】:

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

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

                                            【讨论】:

                                              猜你喜欢
                                              • 2022-10-09
                                              • 1970-01-01
                                              • 1970-01-01
                                              • 2013-05-01
                                              • 1970-01-01
                                              • 2023-04-08
                                              • 2022-06-10
                                              • 2019-09-09
                                              • 1970-01-01
                                              相关资源
                                              最近更新 更多