如何解锁SQLite数据库?

时间:2008-09-29 22:35:49

标签: sqlite

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

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

37 个答案:

答案 0 :(得分:234)

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

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

  

$ fuser development.db

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

  

> development.db:5430

刚刚杀死这个过程...

  

kill -9 5430

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

答案 1 :(得分:86)

我在写入期间因使应用程序崩溃而导致我的sqlite数据库被锁定。以下是我修复它的方法:

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

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

答案 2 :(得分:51)

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

本页未解释的是SQLite如何判断您的进程中的某些内容是否存在锁定以及哪些条件可能导致误报。

答案 3 :(得分:29)

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

答案 4 :(得分:13)

如果要删除“数据库已锁定”错误,请执行以下步骤:

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

答案 5 :(得分:12)

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

答案 6 :(得分:10)

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

答案 7 :(得分:9)

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

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

答案 8 :(得分:5)

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

使用可能是......

的Linux shell
mv mydata.db temp.db
cp temp.db mydata.db

答案 9 :(得分:4)

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

答案 10 :(得分:4)

我添加了#34; Pooling=true"连接字符串,它工作。

答案 11 :(得分:4)

我发现SQLite中各种锁定状态的documentation非常有用。迈克尔,如果你可以执行读操作但不能对数据库执行写操作,这意味着进程已经对数据库进行了RESERVED锁定但尚未执行写入。如果您正在使用SQLite3,那么有一个名为PENDING的新锁,其中不允许连接任何进程,但现有连接可以执行读取,因此如果这是问题,您应该查看它。

答案 12 :(得分:3)

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

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

我会重申,因为它很重要 - 解决方案不是找到锁定程序并将其删除 - 这是为了找出数据库是否有充分理由的写锁定,并从那里开始。有时,正确的解决方案只是喝咖啡休息时间。

创建这种锁定但未写入状态的唯一方法是,如果您的程序运行BEGIN EXCLUSIVE,因为它想要进行一些表格更改或某些事情,然后由于某种原因从未发送过END之后,并且流程永不终止。任何正确编写的代码都不太可能满足所有这三个条件,并且当有人想杀死他们的锁定过程时,这样的99次中有100次,锁定过程实际上是锁定数据库的原因。程序员通常不会添加BEGIN EXCLUSIVE条件,除非他们确实需要,因为它会阻止并发并增加用户投诉。 SQLite本身只在真正需要时添加它(比如索引时)。

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

答案 13 :(得分:3)

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

请勿忘记致电:

sqlite_reset(xxx);

sqlite_finalize(xxx);

答案 14 :(得分:2)

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

您可以使用begin transaction和end transaction来防止数据库在将来被锁定。

答案 15 :(得分:2)

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

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

答案 16 :(得分:2)

我的Linux环境中的

lsof 命令帮助我弄清楚一个进程正在挂起以保持文件打开。
杀死了这个过程,问题就解决了。

答案 17 :(得分:2)

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

然而,能够找到根本原因是很好的。

答案 18 :(得分: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数据库文件,请检查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

答案 19 :(得分:1)

我在一个与这里描述的情况略有不同的情况下得到了这个错误。

SQLite数据库驻留在由3台服务器共享的NFS文件系统上。在2个服务器上,我能够成功地对数据库运行查询,第三个服务器认为我正在使用#34;数据库被锁定"消息。

第三台机器的事情是/var上没有剩余空间。每次我试图在这个文件系统中的任何SQLite数据库中运行查询时,我得到了"数据库被锁定"消息以及日志上的此错误:

  

8月8日10:33:38 server01内核:lockd:无法监控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

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

答案 20 :(得分: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 )

答案 21 :(得分:1)

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

答案 22 :(得分:1)

我遇到了同样的错误。 在5个谷歌谷歌之后我发现我没有关闭一个使用数据库的shell。 关闭它然后再试一次;)

答案 23 :(得分: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程序。

答案 24 :(得分:1)

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

答案 25 :(得分:0)

你可以试试这个:.timeout 100来设置超时。 我不知道在命令行中发生了什么,但在C#.Net中我这样做:"UPDATE table-name SET column-name = value;"我得到数据库已锁定,但这个"UPDATE table-name SET column-name = value"它没问题。

看起来当你添加;时,sqlite会寻找更多命令。

答案 26 :(得分:0)

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

答案 27 :(得分:0)

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

  1. 我将sqlite文件下载到我的系统(FTP)
  2. 删除了在线sqlite文件
  3. 将文件上传回托管服务提供商
  4. 现在工作正常。

答案 28 :(得分:0)

我正在"数据库被锁定"多线程应用程序中的错误,似乎是SQLITE_BUSY结果代码,我通过将sqlite3_busy_timeout设置为类似30000的长度来解决它。

(另一方面,在一个7岁的问题上有多奇怪,没有人发现这一点!SQLite确实是一个奇特而神奇的项目......)

答案 29 :(得分:0)

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

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

答案 30 :(得分:0)

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

我已经检查过可能导致数据库锁定的其他进程,例如(SQLite Manager,连接到我的数据库的其他程序)。但是没有其他程序连接到它,它只是在连接的同一个应用程序中的另一个活跃的 SQLConnection

  

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

答案 31 :(得分:0)

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

请停止正在使用特定数据库的进程,然后执行查询。

答案 32 :(得分:0)

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

这可能意味着您已打开并且(EXCLUSIVE?)事务并且尚未提交数据。你的程序或其他进程是否留下了-journal?

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

答案 33 :(得分:0)

如果您尝试将 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

的Mac

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

答案 34 :(得分:0)

我在尝试写入数据时构建的C#.NET 4.6.1应用程序中也收到sqlite锁,但是在我的开发机上的Visual Studio中运行该应用程序时却没有。而是仅在应用程序已安装并在远程Windows 10计算机上运行时才发生。

最初,我认为这是文件系统权限,但是事实证明,我使用Nuget在项目中安装的System.Data.SQLite软件包驱动程序(v1.0.109.2)引起了问题。我删除了NuGet软件包,并在项目中手动引用了较旧版本的驱动程序,并且在远程计算机上重新安装了该应用程序之后,锁定问题神奇地消失了。只能认为最新的驱动程序或Nuget软件包存在错误。

答案 35 :(得分:0)

我已经运行了“用于SQLite的数据库浏览器”工具,并且也在其中工作。显然,该工具还可以锁定事物。 单击“写入更改”或“还原更改”后,锁消失了,其他进程(一个React-Native脚本)不再给出该错误。

{{3}}

答案 36 :(得分:0)

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

例如:

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

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