sqlite3的:: BusyException

现在使用SQLite3运行一个rails站点。

大约每500个请求一次,我得到一个

ActiveRecord :: StatementInvalid(SQLite3 :: BusyException:数据库被locking:…

有什么办法来解决这将是微创入侵我的代码?

目前我正在使用SQLLite,因为您可以将数据库存储在源代码pipe理中,这使得备份变得非常自然,而且您可以快速地将更改推送出去。 但是,显然不是真正为并发访问设置的。 明天早上我将迁移到MySQL。

默认情况下,如果数据库处于忙碌和locking状态,sqlite会立即返回一个阻塞的忙碌错误。 你可以要求它等待,并继续尝试一段时间,然后放弃。 这通常解决了这个问题,除非你有1000线程访问你的数据库,当我同意SQLite将是不合适的。

    如果数据库被locking,//设置SQLite等待并重试长达100ms
     sqlite3_busy_timeout(db,100);

你提到这是一个Rails站点。 Rails允许你在你的database.ymlconfiguration文件中设置SQLite重试超时:

production: adapter: sqlite3 database: db/mysite_prod.sqlite3 timeout: 10000 

超时值以毫秒为单位指定。 将其增加到10或15秒将会减less在日志中看到的BusyException的数量。

但这只是一个临时的解决scheme。 如果您的站点需要真正的并发性,那么您将不得不迁移到另一个数据库引擎。

所有这些事情都是真实的,但它不回答这个问题,这可能是:为什么我的Rails应用程序偶尔会在生产中引发SQLite3 :: BusyException?

@Shalmanese:什么是生产托pipe环境? 它在共享主机上吗? 是在NFS共享上包含sqlite数据库的目录? (可能在共享主机上)。

这个问题可能与NFS共享和SQLite缺乏并发性的文件locking有关。

只是为了logging。 在Rails 2.3.8的一个应用程序中,我们发现Rails忽略了Rifkin Habsburg提出的“超时”选项。

经过一番调查,我们在Rails dev中发现了一个可能相关的错误: http : //dev.rubyonrails.org/ticket/8811 。 经过一些更多的调查,我们find了解决scheme (使用Rails 2.3.8进行testing):

编辑这个ActiveRecord文件:activerecord-2.3.8 / lib / active_record / connection_adapters / sqlite_adapter.rb

replace这个:

  def begin_db_transaction #:nodoc: catch_schema_changes { @connection.transaction } end 

  def begin_db_transaction #:nodoc: catch_schema_changes { @connection.transaction(:immediate) } end 

就这样! 我们没有注意到性能下降,现在应用程序支持更多的请求没有中断(它等待超时)。 Sqlite很好!

 bundle exec rake db:reset 

它为我工作,它会重置并显示待处理的迁移。

来源: 这个链接

 - 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(...) 

Sqlite可以让其他进程等待,直到当前的一个完成。

我使用这条线来连接,当我知道我可能有多个进程试图访问Sqlite数据库:

conn = sqlite3.connect('filename', isolation_level ='exclusive'

根据Python Sqlite文档:

您可以通过isolation_level参数调用connect()或者通过连接的isolation_level属性来控制pysqlite隐式执行哪种types的BEGIN语句(或根本不执行)。

我有一个与rake db:migrate类似的问题。 问题在于工作目录在SMB共享上。 我通过将文件夹复制到我的本地计算机来修复它。

如果您遇到此问题,但增加超时并不会改变任何内容 ,那么您可能会遇到另一个与事务有关的并发问题,下面是总结:

  1. 开始交易(获得共享锁)
  2. 从数据库中读取一些数据(我们仍然使用SHARED锁)
  3. 同时,另一个进程启动事务并写入数据(获取RESERVED锁)。
  4. 然后你尝试写,你现在试图请求保留
  5. SQLite 立即引发SQLITE_BUSYexception(独立于您的超时),因为之前的读取在获得RESERVEDlocking时可能不再准确。

解决这个问题的一种方法是修补active_record sqlite适配器,直接在事务开始时通过将:immediate选项填充到驱动程序来获得一个RESERVED锁。 这会降低性能,但是至less你所有的交易都会尊重你的超时,并且一个接一个地发生。 这里是如何使用prepend (Ruby 2.0+)把它放在初始化程序中:

 module SqliteTransactionFix def begin_db_transaction log('begin immediate transaction', nil) { @connection.transaction(:immediate) } end end module ActiveRecord module ConnectionAdapters class SQLiteAdapter < AbstractAdapter prepend SqliteTransactionFix end end end 

阅读更多: https : //rails.lighthouseapp.com/projects/8994/tickets/5941-sqlite3busyexceptions-are-raised-immediately-in-some-cases-despite-setting-sqlite3_busy_timeout

遇到锁时,哪个表正被访问?

你有长期交易吗?

你可以找出哪些请求仍然在处理锁时遇到?

阿格 – 这是我上个星期存在的祸根。 当任何进程写入数据库时,Sqlite3locking数据库文件。 IE的任何UPDATE / INSERTtypes的查询(由于某种原因也select计数(*))。 但是,它处理多个读取就好了。

所以,我终于感到沮丧,写数据库调用我自己的线程locking代码。 通过确保应用程序在任何时候只能有一个线程写入数据库,我可以扩展到1000个线程。

而且,它是缓慢的地狱。 但它也足够快, 正确 ,这是一个很好的财产。

我在sqlite3 ruby​​扩展中发现了一个死锁,并在这里修复它:一起去看看这是否解决了你的问题。


     https://github.com/dxj19831029/sqlite3-ruby

我打开了一个拉请求,没有他们的回应。

无论如何,预计一些繁忙的exception,如sqlite3本身所述。

注意这个情况: sqlite繁忙


    繁忙处理程序的存在并不保证它会在有时被调用 
    锁争用。 如果SQLite确定调用忙处理程序可能会导致一个 
    死锁,它会继续并返回SQLITE_BUSY或SQLITE_IOERR_BLOCKED而不是 
    调用繁忙的处理程序。 考虑一个进程持有读锁的场景 
    它试图提升到一个保留的锁,第二个进程保留一个保留 
    它正尝试将其提升为独占锁。 第一个过程不能继续 
    因为它被第二个阻塞,第二个过程因为它而不能继续 
    被第一个阻挡。 如果两个进程都调用繁忙的处理程序,则不会生成任何进程 
    进展。 因此,SQLite为第一个进程返回SQLITE_BUSY,希望这一点 
    将导致第一个进程释放它的读锁,并允许第二个进程 
    继续。

如果你遇到这种情况,超时是无效的。 为了避免这种情况,不要把select放在begin / commit里面。 或者使用独占锁来开始/提交。

希望这可以帮助。 🙂

这通常是多个进程访问相同数据库的连续错误,即如果RubyMine中没有设置“仅允许一个实例”标志

尝试运行以下,它可能有所帮助:

 ActiveRecord::Base.connection.execute("BEGIN TRANSACTION; END;") 

来自: Ruby:SQLite3 :: BusyException:数据库被locking:

这可能会清除任何阻碍系统的交易

我相信这发生在一个交易超时。 你真的应该使用“真实”的数据库。 像Drizzle或MySQL。 什么原因为什么你喜欢SQLite超过前两个选项?