Python / SQLite - 数据库被锁定即使超时已久
我知道我可能漏掉了一些很明显的东西,但我就是搞不懂为什么我的pysqlite脚本总是因为“数据库被锁定”而崩溃。我有两个脚本,一个是用来往数据库里加载数据,另一个是用来读取数据的,但这两个脚本经常会因为对数据库的操作互相干扰而崩溃。我把两个脚本的超时时间都设置成了30秒:
cx = sqlite.connect("database.sql", timeout=30.0)
我觉得我能看到一些超时的迹象,比如偶尔在我的Curses格式输出屏幕中间会出现一些时间戳(例如0.12343827e-06 0.1 - 我该怎么阻止它被打印出来?),但从来没有接近30秒的延迟,然而还是有一个脚本不断崩溃。我在一台64位的4 CPU HS21 IBM刀片服务器上运行着RHEL 5.4,听说过一些关于多线程的问题,不知道这是否相关。我使用的包是sqlite-3.3.6-5和python-sqlite-1.1.7-1.2.1,升级到Red Hat官方提供之外的新版本对我来说不是一个好选择。虽然可以,但由于环境的原因不太理想。
之前我在两个脚本中都设置了autocommit=1
,但现在都禁用了,现在在插入数据的脚本中使用cx.commit()
,而在选择数据的脚本中不提交。最终因为我只有一个脚本在做修改,我不明白为什么会出现这种锁定情况。我注意到随着数据库的增大,这种情况变得更严重。最近数据库大小为13 MB,有3个相同大小的表,大约是一整天的数据。创建一个新文件显著改善了这个问题,这也可以理解,但超时时间似乎根本没有被遵守。
非常感谢任何指点。
编辑:在提问后,我稍微重构了一下代码,使用信号每5秒定期写入0到150条更新,这显著减少了锁定的发生频率,从每分钟一次减少到每小时不到一次。我想我可以进一步确保在读取数据的脚本中,写入数据的时间错开几秒,但从根本上说,我是在绕过一个我认为存在的问题,这样做让超时变得不必要,这似乎还是不太对。谢谢。
4 个回答
SQLite这个数据库其实并不适合处理写入量很大的工作负载,它也不假装自己能做到这一点(不过它在一次事务中可以写入很多数据)。听起来你可能到了需要换一个数据库的地步,比如MySQL、PostgreSQL、Oracle或者DB2。这些选择中有些确实比较贵,但对于某些工作负载来说,这就是你需要的解决方案。(另外,处理写入量大的工作时,使用专门的数据库服务器通常效果更好,尽管这样会增加部署的成本和复杂性。有些事情就是需要花钱的。)
SQLite在每次写入(比如更新、插入、删除等)时都会使用数据库锁。我个人认为,这个锁会一直保持到事务结束为止。这个锁是跨线程和进程的,尽我所知。
所以,我会尝试在写入脚本中明确结束事务和连接,并且在读取脚本中也明确提交,来调试并发问题。
在早期版本的pysqlite中,sqlite.connect
里的timeout
参数似乎是以毫秒为单位来理解的。所以如果你写timeout=30.0
,实际上应该写成timeout=30000
。