我如何解锁SQLite数据库?
sqlite> DELETE FROM mails WHERE (`id` = 71); SQL error: database is locked
如何解锁数据库,这样可以工作?
在Windows中,你可以尝试这个程序http://www.nirsoft.net/utils/opened_files_view.html找出进程正在处理db文件。; 试试closures解锁数据库的程序
在Linux和MacOS中,您可以做类似的事情,例如,如果您的locking文件是development.db:
$ fuser development.db
这个命令将显示哪个进程正在locking文件:
> development.db:5430
只要杀死这个过程…
杀-9 5430
…你的数据库将被解锁。
我导致我的sqlite数据库在写入过程中崩溃的应用程序locking。 这是我如何修复它:
echo ".dump" | sqlite old.db | sqlite new.db
取自: http : //random.kakaopor.hu/how-to-repair-an-sqlite-database
SQLite wiki DatabaseIsLocked页面提供了一个很好的解释这个错误信息。 它部分地指出,争用的根源是内部的(发生错误的过程)。
这个页面没有解释的是,SQLite是如何决定你的进程中的某个东西是locking的,哪些情况会导致误报。
删除-journal文件听起来像一个可怕的想法。 在那里允许sqlite在崩溃之后将数据库回滚到一致的状态。 如果在数据库处于不一致状态时将其删除,则表示数据库已损坏。 从sqlite网站引用一个页面:
如果发生崩溃或断电,磁盘上仍留有热日志,则原始数据库文件和热日志必须保留在磁盘上,并保留其原始名称,直到数据库文件由另一个SQLite进程打开并回退。 […]
我们怀疑SQLite恢复的常见故障模式是这样的:发生电源故障。 电源恢复后,好心的用户或系统pipe理员开始在磁盘上四处查看是否有损坏。 他们看到他们的数据库文件名为“important.data”。 这个文件对他们来说可能是熟悉的。 但是在崩溃之后,还有一个名为“important.data-journal”的热门日志。 用户然后删除热日志,认为他们正在帮助清理系统。 除了用户教育,我们知道无法阻止这一点。
回滚应该在下一次打开数据库时自动发生,但是如果进程无法locking数据库,将会失败。 正如其他人所说的,其中一个可能的原因是目前另一个进程已经开放。 如果数据库位于NFS卷上,则另一种可能性是过时的NFSlocking。 在这种情况下,解决方法是用未在NFS服务器上locking的新副本(mv database.db original.db; cp original.db database.db)replace数据库文件。 请注意,由于NFS文件locking的错误实现,sqlite常见问题解答build议关于并发访问NFS卷上的数据库的警告。
我无法解释为什么删除一个-journal文件可以让你locking一个你以前没有的数据库。 这是可重复的吗?
顺便说一句,存在一个-journal文件并不一定意味着有崩溃或有变化回滚。 Sqlite有几种不同的日记模式,在PERSIST或TRUNCATE模式下,它始终保留-journal文件,并更改内容以指示是否有部分事务回滚。
如果一个进程在SQLite数据库上有一个锁,并且崩溃,数据库会永久保持locking状态。 那就是问题所在。 并不是说其他进程有locking。
SQLite数据库文件只是文件,所以第一步是确保它不是只读的。 另一件事是确保你没有打开数据库的某种GUI SQLite数据库查看器。 您可以在另一个shell中打开数据库,或者您的代码可能会打开数据库。 通常情况下,如果不同的线程或应用程序(如SQLite数据库浏览器)可以打开数据库,则可以看到这一点。
我刚刚有这个问题,使用远程服务器上的SQLite数据库,存储在NFS挂载。 在我使用的远程shell会话在数据库打开时崩溃后,SQLite无法获得locking。
上面提到的恢复配方不适用于我(包括首先移动,然后复制数据库的想法)。 但是,在将其复制到非NFS系统后,数据库变得可用,而不是数据似乎已经丢失。
如果您想删除“数据库已locking”错误,请按照下列步骤操作:
- 将您的数据库文件复制到其他位置。
- 用复制的数据库replace数据库。 这将取消所有正在访问您的数据库文件的进程。
如果文件位于远程文件夹(如共享文件夹)中,则会引发此错误。 我将数据库更改为本地目录,并且完美运行。
我发现在SQLite中locking各种状态的文档非常有帮助。 迈克尔,如果你可以执行读操作,但不能执行写入数据库,这意味着一个进程已经获得了数据库的保留锁,但还没有执行写入。 如果你正在使用SQLite3,那么有一个叫做PENDING的新锁,其中不允许更多的进程连接,但是现有的连接可以执行读操作,所以如果是这个问题,你应该看看。
我的锁是由系统崩溃造成的,而不是由挂起的进程造成的。 为了解决这个问题,我简单地重命名了文件,然后将其复制回原来的名称和位置。
使用Linux的shell,将是…
mv mydata.db temp.db cp temp.db mydata.db
一些函数,如INDEX'ing,可能需要很长时间 – 它会在运行时locking整个数据库。 在这样的情况下,甚至可能不使用日志文件!
所以最好/唯一的方法是检查你的数据库是否被locking,因为一个进程正在写入它(因此你应该把它留在地狱,直到它完成其操作)是md5(或md5sum在某些系统上)该文件两次。 如果你得到一个不同的校验和,数据库正在写入,你真的真的不想杀死那个进程,因为如果你这样做,你可以很容易地结束一个损坏的表/数据库。
我会重申,因为这很重要 – 解决scheme不是findlocking程序并杀死它 – 而是从数据库中找出数据库是否有写锁。 有时正确的解决scheme只是一个rest时间。
创build这个locking但不被写入的唯一方法是如果你的程序运行BEGIN EXCLUSIVE
,因为它想做一些表更改或什么的,那么不pipe什么原因之后永远不会发送END
, 永不终止 。 所有这三个条件在任何正确编写的代码中都是不太可能的,当有人想要杀死它们的locking过程时,这100个数据中有99个是真正的locking数据库的原因。 程序员通常不会添加BEGIN EXCLUSIVE
条件,除非他们确实需要这样做,因为它可以防止并发性并增加用户的投诉。 SQLite本身只在需要的时候才会添加(比如索引)。
最后,“locking”状态不存在于文件中,正如几个答案所述 – 它驻留在操作系统的内核中。 运行BEGIN EXCLUSIVE
的进程已经要求操作系统在文件上加锁。 即使你的独占进程已经崩溃,你的操作系统将能够找出是否应该保持文件locking! 这是不可能的最终locking的数据库,但没有进程正在积极locking它! 当看到哪个进程正在locking文件时,最好使用lsof而不是fuser(这是一个很好的certificate: https : //unix.stackexchange.com/questions/94316/fuser-vs-lsof-检查文件在使用中 )。 另外,如果你有DTrace(OSX),你可以在文件上使用iosnoop。
有可能是另一个进程访问数据库文件 – 你检查LSF?
我刚刚发生了类似的事情 – 我的Web应用程序能够从数据库中读取数据,但无法执行任何插入或更新。 Apache的重启至less暂时解决了这个问题。
但是,能够find根本原因是很好的。
我的Linux环境下的lsof命令帮助我弄清楚,一个进程挂着保持文件打开。
杀死了这个过程,问题解决了。
我在应用程序中有这样的问题,从2个连接访问SQLite – 一个是只读的,另一个是写入和读取。 看起来像是只读连接阻止了第二个连接的写入。 最后,事实certificate,要求在使用后立即完成或至less重置准备好的陈述。 在准备好的语句被打开之前,它导致数据库被阻止写入。
不要忘记呼叫:
sqlite_reset(xxx);
要么
sqlite_finalize(xxx);
这个链接解决了这个问题。 : 当sqlite给:数据库locking的错误它解决了我的问题可能对你有用。
而且您可以使用开始事务和结束事务来locking未来的数据库。
应该是数据库的内部问题…
对于我来说,它试图浏览数据库与“SQLitepipe理器”后performance出来…
所以,如果你不能find另一个进程连接到数据库,你只是不能修复它,只是尝试这个激进的解决scheme:
- 提供导出您的表(您可以使用Firefox上的“SQLitepipe理器”)
- 如果迁移改变你的数据库scheme,删除上次失败的迁移
- 重命名你的“database.sqlite”文件
- 执行“rake db:migrate”来创build一个新的工作数据库
- 提供给数据库正确的权限以便进行表导入
- 导入您的备份表
- 编写新的迁移
- 用“
rake db:migrate
”执行它
我在Mac OS X 10.5.7上遇到了同样的问题,在terminal会话中运行Python脚本。 即使我已经停止脚本,terminal窗口坐在命令提示符下,它会在下次运行时出现此错误。 解决办法是closuresterminal窗口,然后再打开它。 对我没有意义,但它的工作。
我只是有同样的错误。 谷歌5个矿井后,我发现我没有closures一个贝壳女巫正在使用数据库。 closures它,然后再试一次;)
我有同样的问题。 显然,回滚函数似乎用与db文件相同的日志来覆盖db文件,但没有最近的更改。 我已经在下面的代码中实现了这一点,从那以后它一直工作的很好,而在我的代码在数据库一直处于locking状态之前,它只会卡在循环中。
希望这可以帮助
我的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 )
获取此exception的一个常见原因是当您尝试执行写入操作,同时仍保留读取操作的资源时。 例如,如果您从表中SELECT,然后尝试更新所选内容而不先closures您的ResultSet。
在重新启动选项之前,值得看看是否可以findsqlite数据库的用户。
在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程序。
我添加了“ Pooling=true
”到连接string,它工作。
一个老问题,有很多答案,这是我最近阅读上述答案的步骤,但在我的情况下,问题是由于CIFS资源共享。 这种情况以前没有报告过,所以希望能帮到别人。
- 检查你的java代码中没有连接打开。
- 检查没有其他进程正在使用您的SQLite数据库文件lsof。
- 检查正在运行的jvm进程的用户所有者是否拥有对该文件的r / w权限。
-
尝试强制连接打开与locking模式
final SQLiteConfig config = new SQLiteConfig(); config.setReadOnly(false); config.setLockingMode(LockingMode.NORMAL); connection = DriverManager.getConnection(url, config.toProperties());
如果你在一个NFS共享文件夹中使用你的SQLite数据库文件,检查SQLite常见问题的这一点 ,并检查你的安assembly置选项,以确保你避免locking,如下所述:
//myserver /mymount cifs username=*****,password=*****,iocharset=utf8,sec=ntlm,file,nolock,file_mode=0700,dir_mode=0700,uid=0500,gid=0500 0 0
我在这里描述的情况有点不同于这个错误。
SQLite数据库驻留在3个服务器共享的NFS文件系统上。 在2台服务器上,我能够成功地在数据库上运行查询,第三台服务器认为我得到的是“数据库已locking”消息。
这第三台机器的事情是它没有空间留在/var
。 每次我试图在位于这个文件系统的ANY SQLite数据库中运行一个查询时,我得到了“数据库被locking”的消息,并且在日志中也出现这个错误:
8月8日10:33:38 server01内核:locking:无法监视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
空间情况处理完毕后,一切恢复正常。
从你以前的评论你说,一个-journal文件存在。
这可能意味着您已经打开和(EXCLUSIVE?)事务并且还没有提交数据。 你的程序或其他进程是否离开了 – 杂志后面?
重新启动sqlite进程将查看日志文件并清理所有未提交的操作并删除-journal文件。
正如Seun Osewa所说,有时僵尸程序会在terminallocking,即使你不认为这是可能的。 你的脚本运行,崩溃,你回到提示,但有一个僵尸进程产生的图书馆电话的地方,该进程有锁。
closures你在(在OSX上)的terminal可能工作。 重新启动将工作。 你可以寻找没有做任何事情的“python”进程,并杀死它们。
你可以试试这个: .timeout 100
来设置超时。 我不知道在命令行中发生了什么,但是在C#.Net中,当我这样做时: "UPDATE table-name SET column-name = value;"
我得到数据库被locking,但这个"UPDATE table-name SET column-name = value"
它很好。
它看起来像添加时,sqlite会查找更多的命令。
使用Delphi与LiteDAC组件时,出现此错误。 原来,只有在Delphi IDE中运行我的应用程序,如果连接属性被设置为SQLite连接组件(在这种情况下是TLiteConnection)为True的情况下才会发生。