SQLite 异常:SQLite 忙
Posted
技术标签:
【中文标题】SQLite 异常:SQLite 忙【英文标题】:SQLite Exception: SQLite Busy 【发布时间】:2010-11-01 03:24:24 【问题描述】:任何人都可以提供有关此错误的任何输入。我正在尝试使用 Objective C 插入表格。
在执行此操作时,我收到 SQLite Busy 错误。为什么会这样?
【问题讨论】:
你能提供一些示例代码吗?几行来了解发生了什么。 对我来说就像以管理员身份运行命令提示符一样简单。或者,在 UNIX 上,您可以在启动数据库时使用sudo
。
【参考方案1】:
如果在调用 sqlite3 函数时得到错误代码 SQLITE_BUSY,这意味着根据 drdaeman 的观察,数据库已被同一进程或进程中的一个线程锁定。
处理这种情况的正确方法是在循环中尝试操作,如果返回码仍然是SQLITE_BUSY,则等待一段时间(您决定超时值)然后在下一个循环中重试操作迭代。
例如,以下代码 sn-p 取自 Objective C 包装器 FMDB (http://code.google.com/p/flycode/source/browse/trunk/fmdb) 显示了如何为查询准备语句,同时考虑到某些操作可能返回 SQLITE_BUSY:
int numberOfRetries = 0;
BOOL retry = NO;
if (!pStmt)
do
retry = NO;
rc = sqlite3_prepare(db, [sql UTF8String], -1, &pStmt, 0);
if (SQLITE_BUSY == rc)
retry = YES;
usleep(20);
if (busyRetryTimeout && (numberOfRetries++ > busyRetryTimeout))
NSLog(@"%s:%d Database busy (%@)", __FUNCTION__, __LINE__, [self databasePath]);
NSLog(@"Database busy");
sqlite3_finalize(pStmt);
[self setInUse:NO];
return nil;
else if (SQLITE_OK != rc)
if (logsErrors)
NSLog(@"DB Error: %d \"%@\"", [self lastErrorCode], [self lastErrorMessage]);
NSLog(@"DB Query: %@", sql);
if (crashOnErrors)
NSAssert2(false, @"DB Error: %d \"%@\"", [self lastErrorCode], [self lastErrorMessage]);
sqlite3_finalize(pStmt);
[self setInUse:NO];
return nil;
while (retry);
顺便说一句,如果你需要访问 sqlite,相对于通过原生 C API 直接访问而言,FMDB 非常方便,使用起来也简单得多。
【讨论】:
您只需调用sqlite3_busy_timeout即可完成几乎相同的事情。 投反对票。首先,如果有人在做某事,即使是在某个开源项目中,这并不意味着它是“正确的事情”。真正合适的事情是相关图书馆的作者在文档中陈述的内容。 sqlite.org/c3ref/busy_handler.html @Alaksiej N:您是否仔细阅读了您在评论中提供的繁忙处理程序的文档?上面写着:“忙处理程序的存在并不能保证在存在锁争用时会调用它。如果 SQLite 确定调用忙处理程序可能导致死锁,它将继续并返回 SQLITE_BUSY 或 SQLITE_IOERR_BLOCKED 而不是调用忙碌的管理员。”因此,不能保证 SQLite 将始终调用您定义的繁忙处理程序! @MassimoCafaro 是的,但在这种情况下(当阻塞会导致死锁时)你也不应该阻塞。 @AlaksiejN。请注意给定答案的日期:2009。当时可能不存在该特定 API。事实上,如果您查看该项目最近的代码 (github.com/ccgus/fmdb/blob/master/src/FMDatabase.m),他们现在确实调用了该函数。【参考方案2】:如果我没听错,“忙”意味着您无法获得锁。似乎另一个进程(或线程等)锁定了数据库。
File Locking And Concurrency In SQLite Version 3
【讨论】:
【参考方案3】:我在顺序 INSERT INTO 命令上遇到了与 SQLITE_BUSY 类似的问题。第一行插入正常,但是当应用程序尝试插入第二行时,我得到了 SQLITE_BUSY 状态。在谷歌搜索之后,我了解到您必须在执行语句后调用 sqlite3_finalize():http://www.sqlite.org/c3ref/finalize.html。完成我的陈述解决了我的问题。
【讨论】:
【参考方案4】:就我而言,我忘记在使用数据库后关闭它。以下固定我的:
sqlite3_finalize(statement);
sqlite3_close(contactDB);
FMDB 也可以轻松缓解您的这些烦恼。
【讨论】:
【参考方案5】:我知道这已经很晚了,但是如果有人正在寻找有关错误发生原因的更详细解释,请查看https://www.activesphere.com/blog/2018/12/24/understanding-sqlite-busy。我写了这篇文章,希望它可以帮助人们更好地理解 SQLite 中的并发性。
它涵盖了在不同 SQLite 模式(主要是回滚日志和 WAL)中可能发生错误的不同场景。它还研究了正确处理此类错误的方法(使用busy_timeout
重试可能并不总是成功,手动重试单个查询也可能导致死锁)。
【讨论】:
以上是关于SQLite 异常:SQLite 忙的主要内容,如果未能解决你的问题,请参考以下文章
获取sqlite繁忙异常[SQLITE_BUSY]数据库文件被锁定(数据库被锁定)
“SQLite.SQLiteConnection”的类型初始化器抛出异常