SQLite3 :: BusyException
现在使用SQLite3运行Rails站点。
大约每500个请求一次,我得到一个
ActiveRecord :: StatementInvalid(SQLite3 :: BusyException:数据库已锁定:...
有什么办法可以解决这种对我的代码造成最小影响的问题?
目前,我正在使用SQLLite,因为我们可以将数据库存储在源代码管理中,这使备份自然进行,并且可以非常迅速地推出更改。但是,显然并没有为并发访问设置它。我明天早上将迁移到MySQL。
解决方案
回答
我相信这会在交易超时时发生。我们确实应该使用"真实"数据库。像Drizzle或者MySQL。为什么我们比之前的两个选项更喜欢SQLite?
回答
来源:此链接
- Open the database db = sqlite3.open("filename") -- Ten attempts are made to proceed, if the database is locked function my_busy_handler(attempts_made) if attempts_made < 10 then return true else return false end end -- Set the new busy handler db:set_busy_handler(my_busy_handler) -- Use the database db:exec(...)
回答
遇到锁定时正在访问哪个表?
我们是否有长期交易?
我们能找出遇到锁定时仍在处理哪些请求吗?
回答
上个礼拜,我的生存祸根啊。当任何进程写入数据库时,Sqlite3都会锁定db文件。 IE浏览器的任何UPDATE / INSERT类型查询(出于某种原因也请选择count(*))。但是,它可以处理多次读取。
因此,我终于感到沮丧,无法在数据库调用周围编写自己的线程锁定代码。通过确保应用程序在任何时候只能有一个线程写入数据库,我能够扩展到1000个线程。
是的,它慢得要命。但是它也足够快且正确,这是一个不错的属性。
回答
默认情况下,如果数据库处于忙碌状态且已锁定,则sqlite立即返回一个阻塞的,忙碌的错误。我们可以要求它等待一段时间,然后再尝试放弃。通常,这可以解决问题,除非我们确实有数千个线程在访问数据库,否则我认为sqlite是不合适的。
// set SQLite to wait and retry for up to 100ms if database locked sqlite3_busy_timeout( db, 100 );
回答
我们提到这是一个Rails网站。 Rails允许我们在database.yml配置文件中设置SQLite重试超时:
production: adapter: sqlite3 database: db/mysite_prod.sqlite3 timeout: 10000
超时值以毫秒为单位指定。将其增加到10或者15秒应该会减少我们在日志中看到的BusyExceptions的数量。
不过,这只是一个临时解决方案。如果站点需要真正的并发,那么我们将不得不迁移到另一个数据库引擎。
回答
Sqlite可以允许其他进程等到当前进程完成。
当我知道可能有多个进程试图访问Sqlite DB时,我使用这条线进行连接:
conn = sqlite3.connect('文件名',isolation_level ='独占')
根据Python Sqlite文档:
You can control which kind of BEGIN statements pysqlite implicitly executes (or none at all) via the isolation_level parameter to the connect() call, or via the isolation_level property of connections.
回答
所有这些事情都是正确的,但它并不能回答问题,这很可能是:为什么我的Rails应用偶尔会在生产中引发SQLite3 :: BusyException?
@Shalmanese:生产托管环境是什么样的?它在共享主机上吗? NFS共享上是否包含sqlite数据库的目录? (就像在共享主机上一样)。
此问题可能与NFS共享的文件锁定现象以及SQLite缺乏并发现象有关。