sqlite> DELETE FROM mails WHERE (`id` = 71);
SQL error: database is locked
我该如何解锁数据库才能正常工作?
sqlite> DELETE FROM mails WHERE (`id` = 71);
SQL error: database is locked
我该如何解锁数据库才能正常工作?
Answers:
在Windows中,您可以尝试使用该程序http://www.nirsoft.net/utils/opened_files_view.html找出正在处理db文件的过程。尝试关闭该程序以解锁数据库
在Linux和macOS中,您可以执行类似的操作,例如,如果锁定文件为development.db:
$热熔器development.db
此命令将显示什么进程正在锁定文件:
> development.db:5430
只是杀死进程...
杀死-9 5430
...并且您的数据库将被解锁。
kill
应该没问题,但是您需要小心地杀死它,这kill -9
可能是错误的和/或过大的杀伤力。如果该进程已挂起并且不会以其他方式终止,那么有时您确实需要kill -9
。但是,您不想去干掉主要的生产工作,而是可以报告数据库已不再锁定!
我通过写操作导致应用崩溃导致我的sqlite数据库被锁定。这是我固定的方法:
echo ".dump" | sqlite old.db | sqlite new.db
摘自:http : //random.kakaopor.hu/how-to-repair-an-sqlite-database
sqlite> .dump PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; /**** ERROR: (5) database is locked *****/ ROLLBACK; -- due to errors
FOREIGN KEY constraint failed (RELEASE RESTOREPOINT)
下面列出的DatabaseIsLocked页面不再可用。“文件锁定和并发”页面描述了与v3中引入的文件锁定有关的更改,可能对以后的读者有用。https://www.sqlite.org/lockingv3.html
SQLite Wiki DatabaseIsLocked页面对此错误消息提供了很好的解释。它部分说明争用的源是内部的(对于发出错误的过程而言)。
该页面没有解释的是SQLite如何确定您的进程中的某些内容已锁定,以及哪些条件可能导致误报。
删除-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常见问题解答建议您谨慎访问NFS卷上的数据库。
我无法解释为什么删除-journal文件会使您锁定以前无法访问的数据库。那是可复制的吗?
顺便说一句,-journal文件的存在并不一定意味着发生了崩溃或有待回滚的更改。Sqlite有几种不同的日志模式,在PERSIST或TRUNCATE模式下,它将-journal文件始终保留在原位,并更改内容以指示是否有部分事务要回滚。
我的锁定是由系统崩溃而不是由挂起进程引起的。为了解决这个问题,我只是简单地重命名了文件,然后将其复制回其原始名称和位置。
使用Linux shell将是...
mv mydata.db temp.db
cp temp.db mydata.db
我发现有关SQLite锁定的各种状态的文档非常有用。迈克尔,如果您可以执行读取操作但不能执行对数据库的写入操作,则意味着进程已在数据库上获得了RESERVED锁,但尚未执行写入操作。如果您使用的是SQLite3,则有一个名为PENDING的新锁,该锁不允许再有更多的进程连接,但是现有的连接会阻止执行读取操作,因此,如果这是问题,您应该考虑一下。
我在应用程序中遇到了此类问题,该问题可通过2个连接访问SQLite-一个是只读的,第二个用于读写。看起来该只读连接阻止了第二连接的写入。最后,事实证明,使用后需要立即完成或至少重置准备好的语句。直到打开准备好的语句,它才导致数据库被阻止写入。
不要忘记打电话:
sqlite_reset(xxx);
要么
sqlite_finalize(xxx);
某些功能(例如INDEX'ing)可能会花费很长时间-并且在运行时会锁定整个数据库。在这种情况下,它甚至可能不使用日志文件!
因此,最好的/唯一的检查数据库是否已锁定的最佳方法是因为某个进程正在主动向其写入数据(因此,在完成其操作之前,您应将其搁置一旁)是对文件md5(或某些系统上的md5sum)进行两次。如果您获得不同的校验和,则说明数据库正在写入中,并且您真的真的不想终止-9这个过程,因为这样做很容易导致损坏的表/数据库。
我重申一下,因为它很重要-解决方案不是找到锁定程序并杀死它-而是找到数据库是否有写锁是有充分理由的,然后从那里开始。有时正确的解决方案只是喝咖啡休息时间。
创建此锁定但未写入的情况的唯一方法是程序运行 BEGIN EXCLUSIVE
,因为它想进行一些表更改或其他操作,则无论出于何种原因,它都永远不会发送END
后续消息,并且该过程也不会终止。在任何正确编写的代码中,这三个条件都很难满足,因此,当某人想要杀死-9他们的锁定过程时,有100的99倍,锁定过程实际上是有充分的理由锁定数据库。程序员BEGIN EXCLUSIVE
除非真正需要,否则通常不会添加条件,因为这会阻止并发并增加用户投诉。SQLite本身仅在确实需要时(例如在建立索引时)添加它。
最后,正如几个答案所述,在文件内部不存在“锁定”状态-它位于操作系统的内核中。其运行进程BEGIN EXCLUSIVE
已经从OS请求的锁被放置在该文件。即使您的独占进程崩溃了,您的操作系统也可以弄清楚它是否应该保持文件锁定!最终无法获得已锁定的数据库,但是没有进程正在主动锁定它!当要查看哪个进程正在锁定文件时,通常最好使用lsof而不是fuser(这很好地说明了原因:https : //unix.stackexchange.com/questions/94316/fuser-vs-lsof-查看使用中的文件)。或者,如果您有DTrace(OSX),则可以在文件上使用iosnoop。
此链接解决了问题。:当Sqlite给出:数据库锁定错误 它解决了我的问题可能对您有用。
而且,您可以使用开始事务和结束事务来将来不再使数据库锁定。
应该是数据库的内部问题...
对我来说,它是在尝试使用“ SQLite管理器”浏览数据库后才表现出来的...
因此,如果找不到另一个连接到数据库的进程并且只是无法修复它,只需尝试以下根本解决方案:
rake db:migrate
” 执行我有同样的问题。显然,回滚功能似乎用与日志文件相同的日志覆盖了db文件,但是没有最新的更改。我已经在下面的代码中实现了它,此后一直运行良好,而在此之前,由于数据库保持锁定状态,我的代码只会陷入循环。
希望这可以帮助
##############
#### 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 )
我也在多线程应用程序中也遇到“数据库已锁定”错误,这似乎是SQLITE_BUSY结果代码,我通过设置sqlite3_busy_timeout解决了为适当的长于30000的方法来。
(附带说明,在一个7年的历史上,没有人发现这个问题是多么奇怪!SQLite确实是一个奇特而神奇的项目...)
一个古老的问题,有很多答案,这是我最近在阅读上面的答案时遵循的步骤,但就我而言,问题是由于cifs资源共享造成的。以前没有此案例的报道,因此希望对您有所帮助。
尝试通过以下方式在连接开口上强制使用锁定模式:
final SQLiteConfig config = new SQLiteConfig();
config.setReadOnly(false);
config.setLockingMode(LockingMode.NORMAL);
connection = DriverManager.getConnection(url, config.toProperties());
如果您使用过NFS共享文件夹的SQLite数据库文件,检查了这一点 SQLite的常见问题,并检查您的安装配置选项,以确保您避免了锁,描述在这里:
//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文件系统上。在其中两台服务器上,我能够在数据库上成功运行查询,而在第三台服务器上,我则收到了“数据库已锁定”消息。
这第三台机器的问题是它没有剩余空间了/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的SM_MON为172.22.84.87
处理好空间情况后,一切恢复正常。
如果您尝试解锁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
从先前的评论中,您说到存在-journal文件。
这可能意味着您已经打开和(独占?)事务并且尚未提交数据。您的程序或其他进程是否没有将-journal留下?
重新启动sqlite进程将查看日志文件并清理所有未提交的操作并删除-journal文件。