代码之家  ›  专栏  ›  技术社区  ›  ryantm

如何解锁SQLite数据库?

  •  224
  • ryantm  · 技术社区  · 16 年前
    sqlite> DELETE FROM mails WHERE (`id` = 71);
    SQL error: database is locked
    

    35 回复  |  直到 16 年前
        1
  •  294
  •   guruz    8 年前

    在windows中,您可以尝试此程序 http://www.nirsoft.net/utils/opened_files_view.html

    >development.db:5430

    只要停止这个过程。。。

    …您的数据库将被解锁。

        2
  •  94
  •   robert    13 年前

    我在写入过程中崩溃了一个应用程序,导致我的sqlite db被锁定。下面是我如何修复它的:

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

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

        3
  •  53
  •   Ярослав Рахматуллин    3 年前

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


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

        4
  •  33
  •   Community CDub    4 年前

    删除日志文件听起来是个糟糕的主意。它允许sqlite在崩溃后将数据库回滚到一致状态。如果在数据库处于不一致状态时将其删除,则会留下损坏的数据库。引用《圣经》中的一页 sqlite site :

    我们怀疑SQLite恢复的常见故障模式如下:发生电源故障。恢复电源后,善意的用户或系统管理员开始查看磁盘是否损坏。他们看到了名为“important.data”的数据库文件。他们可能对这个文件很熟悉。但在崩溃之后,也有一个名为“important.data journal”的热门杂志。然后,用户删除热日志,认为它们有助于清理系统。除了用户教育之外,我们知道没有其他方法可以防止这种情况。

    我无法解释为什么删除日志文件会让您锁定以前无法锁定的数据库。这是可复制的吗?

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

        5
  •  30
  •   animuson    12 年前

    1. 将数据库文件复制到其他位置。
        6
  •  14
  •   Phil Phil    16 年前

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

        7
  •  13
  •   Heat Miser    16 年前

        8
  •  12
  •   Ben L    15 年前

    使用一个linux shell,它将是。。。

    mv mydata.db temp.db
    cp temp.db mydata.db
    
        9
  •  11
  •   jogojapan    13 年前

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

        10
  •  7
  •   shA.t Rami Jamleh    7 年前

    我补充说“ Pooling=true “连接到连接字符串,它工作了。

        11
  •  4
  •   Kyle Cronin    16 年前

    我找到了 documentation

        12
  •  4
  •   Zequez    12 年前

    如果文件位于远程文件夹(如共享文件夹)中,则可能引发此错误。我把数据库改为本地目录,它工作得很好。

        13
  •  3
  •   Mike Keskinov    13 年前

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

    sqlite_reset(xxx);
    

    sqlite_finalize(xxx);
    
        14
  •  3
  •   Community CDub    8 年前

    如果您得到一个不同的校验和,那么数据库正在被写入,并且您真的不想终止-9这个进程,因为如果这样做,很容易导致表/数据库损坏。

    我要重申,因为这很重要-解决方案不是找到并杀死锁定程序-而是找到数据库是否有写锁的原因,并从那里开始。有时候,正确的解决办法就是休息一下喝杯咖啡。

    创建此锁定但未写入的情况的唯一方法是程序是否运行 BEGIN EXCLUSIVE ,因为它想做一些表格修改之类的事情,所以无论出于什么原因,它都不会发送 END 这个过程永远不会结束 . 所有这三个条件在任何正确编写的代码中都不太可能得到满足,因此,当有人想要杀死-9他们的锁定进程时,100次中有99次锁定进程实际上是出于一个很好的理由锁定数据库。程序员通常不会添加 条件,除非他们真的需要,因为它会阻止并发并增加用户投诉。SQLite本身只在真正需要时添加它(如索引时)。

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

        15
  •  2
  •   Michael Cox    16 年前

    我也遇到了类似的情况——我的web应用程序能够读取数据库,但无法执行任何插入或更新。Apache的重新启动至少暂时解决了这个问题。

        16
  •  2
  •   PinkSheep    13 年前

    lsof
    终止了流程并解决了问题。

        17
  •  2
  •   Community CDub    8 年前

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

    并且您可以使用BeginTransaction和EndTransaction来避免将来锁定数据库。

        18
  •  2
  •   shA.t Rami Jamleh    7 年前


    对我来说,在尝试使用“SQLite管理器”浏览数据库之后,它就表现出来了。。。
    所以,如果您找不到另一个连接到数据库的进程,并且无法修复它,

    1. 如果迁移更改了数据库方案,请删除上次失败的迁移
    2. 重命名“database.sqlite”文件
    3. 导入备份的表
    4. 编写新的迁移
    5. 执行它时使用“ rake db:migrate
        19
  •  1
  •   Shawn Swaner    15 年前

        20
  •  1
  •   MightyPixel    13 年前

    我只是犯了同样的错误。 在谷歌搜索了5次地雷后,我发现我没有关闭一个正在使用db的炮弹。 只需关闭它,然后重试;)

        21
  •  1
  •   Jay    13 年前

    我也有同样的问题。显然,rollback函数似乎用与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
  •  1
  •   Mar    12 年前

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

        23
  •  1
  •   Stijn Sanders    9 年前

    SQLITE_BUSY 结果代码,我用设置解决了它 sqlite3_busy_timeout 长到三万左右。

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

        24
  •  1
  •   Serge Stroobandt    7 年前

    在使用重新启动选项之前,有必要先看看是否可以找到sqlite数据库的用户。

    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
    

        25
  •  1
  •   shA.t Rami Jamleh    7 年前

    • 检查java代码中没有打开的连接。
    • 检查没有其他进程将SQLite db文件与lsof一起使用。
    • 尝试在打开的连接上强制锁定模式

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

    this point 请参阅SQLite常见问题解答,并查看安装配置选项,以确保避免锁定,如所述 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
  •  1
  •   shA.t Rami Jamleh    7 年前

    我在一个与这里描述的稍有不同的场景中得到了这个错误。

    /var . 每次我尝试在位于该文件系统中的任何SQLite数据库中运行查询时,都会收到“database is locked”(数据库已锁定)消息,并且在日志中出现此错误:

    八月8日10:33:38服务器01内核:锁定:无法监视172.22.84.87

    八月8日10:33:38 server01 rpc.statd[7430]:1987年12月22日SM_MON的STAT_失败到server01

    太空情况得到处理后,一切恢复正常。

        27
  •  1
  •   Bob Stein    7 年前

    如果您试图解锁 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
  •   Siwei    4 年前

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

        29
  •  0
  •   daivd cameron daivd cameron    16 年前

    这可能意味着您已打开和(独占?)事务,但尚未提交数据。您的程序或其他过程是否将-日志留下了??

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

        30
  •  0
  •   wisty    15 年前

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