Sqlite3 database file is locked 解决办法 与sqlite_reset()

本文分享了解决SQLite3数据库文件被锁定的问题经验。通过详细记录测试过程,最终发现在查询结束后调用sqlite_reset()可以避免数据库文件锁定,进而允许正常删除数据表。

有几天没有更新博文了,这几天参加公司的年会,泡温泉,滑雪,玩得不亦乐乎。作为年会后的第一个工作日,自己终于完成了持续多日的sqlite3数据库测试并解决其中的一个问题,就是database file is locked。

在我们的产品中,我们会new出一个database对象,然后调用open方法打开指定路径下的数据库,如果没有这个数据库,就会自动给用户创建一个。这也是sqlite3 db.sqlite 命令的逻辑。在测试中我发现,如果我调用了sqlite3的函数

sqlite_prepare,sqlite_reset,sqlite_step,sqlite_column_text(),方法后,该数据表就不能被删除了,报的错误码是5,代表database file被锁住了。未解决这个问题,首先就是求救互联网,但是网上很多都是关于多线程的问题,在我们的项目不存在多线程的问题。自己只好自己慢慢一个一个排除。

终于在一个偶然的测试中,自己发现是在查询结束后,没有进行sqlite_reset(),当我进行reset 之后,就可以删除该数据表了。查询的顺序就变为了sqlite_prepare,sqlite_reset,sqlite_step,sqlite_column_text(),sqlite_reset()有人可能会疑问,为什么没有在查询完后调用sqlite_finalize()。在我们的项目中,结果集存在于一个变量中,设计这个变量能不断调用,所以没有选择释放这个查询结果集。而释放结果集的工作我们放到了close函数中,这是我们自己封装的函数,在释放这个结果集资源的同事,断开连接。

为什么调用reset()之后就可以删除了呢,自己也没有答案,需要后面进一步的研究,在这里贴出来,以供大家查询。

解决这个bug之后,自己突然想起以前做生物实验时候,一步步验证排除实验不确定因素的过程。当然这个过程比我上面提到的过程复杂多了。万物还是很多通性的呀。

### 解决 SQLite 数据库文件被锁定的问题 当遇到 `SQLITE_BUSY` 错误码时,这通常意味着数据库正忙于处理另一个请求,从而阻止了当前的操作。为了避免这种情况并有效管理并发访问,可以采取多种策略。 #### 使用 `sqlite3_busy_timeout` 通过设置超时时间来等待锁释放是一个常见做法。如果在指定的时间内未能获得锁,则会抛出异常或返回错误。此功能可以通过调用 `sqlite3_busy_timeout()` 函数实现[^1]: ```c int sqlite3_busy_timeout(sqlite3*, int ms); ``` 参数中的 `ms` 表示毫秒数,在这段时间里程序将继续尝试获取锁而不是立即失败。这样可以在一定程度上缓解因短暂竞争而导致的锁定问题。 #### 实现自定义繁忙处理器 另一种更灵活的方法是注册一个回调函数作为忙碌处理器(`busy handler`)。每当发生冲突时就会触发该回调,允许应用程序执行特定逻辑决定是否继续重试或其他行为调整。使用 `sqlite3_busy_handler()` 可以为连接对象配置这样的处理器[^3]: ```c int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*); ``` 第一个参数是要关联的数据库连接;第二个参数是指向回调函数的指针,它接收两个输入——用户数据指针和已经发生的重试次数,并应返回非零值以指示进一步重试;最后一个参数则是传递给回调函数的数据指针。 #### 调整事务粒度优化查询性能 减少长时间持有写入锁的机会同样重要。确保每次只提交必要的更改量,并尽可能缩短读取期间占用共享锁的时间长度。此外,优化 SQL 查询语句也有助于加快整体响应速度,降低死锁风险[^4]。 #### 配置合适的日志模式 SQLite 支持不同的同步级别 (`PRAGMA synchronous`) 和日志持久化选项 (`WAL mode`) 来平衡安全性和效率之间的关系。启用 Write-Ahead Logging (WAL) 模式能够显著改善多读者场景下的吞吐量表现,因为它允许多个客户端几乎同时读取同一份副本而不互相干扰[^2]。 ```sql -- 设置为 NORMAL 同步等级可提高 I/O 性能但仍保持一定安全性 PRAGMA synchronous=NORMAL; -- 开启 WAL 日志方式增强并发能力 PRAGMA journal_mode=WAL; ``` 以上措施结合起来可以帮助有效地应对大多数情况下由 `SQLITE_BUSY` 引起的问题,同时也提高了系统的稳定性和可靠性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值