【问题标题】:ActiveRecord, Sqlite3, and BusyExceptionActiveRecord、Sqlite3 和 BusyException
【发布时间】:2011-08-24 10:21:13
【问题描述】:

我有一个配置了混合 mysql 和 sqlite3 db 连接的 rails 应用程序,为了将特定模型与 sqlite3 相关联,我在每个类定义中添加了一个“建立连接'sqlite_db_config_name'”行。

当我尝试单独保存任何与 sqlite3 连接的模型对象时,保存成功,但是当我尝试保存由其他对象组成的对象时(通过 has_many),我得到一个 BusyException。我有一种感觉,这是因为每个对象都有自己与数据库的连接,并且顶级对象锁定数据库然后调用成员对象的保存方法并且它们无法获取锁定。

我假设有一种方法可以完成这项工作,但我使用的建立连接不正确。

还有人遇到这个吗?

database.yml 配置:

开发者:

development:
  adapter: mysql
  database: maindb
  username: root
  password:
  host: localhost

sqlite:
  adapter: sqlite3
  database: db/db.sqlite3
  timeout: 15000

模型定义:

class Foo < ActiveRecord::Base
  establish_connection 'sqlite'
  belongs_to :bar
end

class Bar < ActiveRecord::Base
  establish_connection 'sqlite'
  has_many :foo  
  def addFoo(item)
    self.foos << item
  end
end

class MysqlModel < ActiveRecord::Base
end

其他:

Ruby 1.8.7
Rails 2.3.4
Ubuntu 10.04

更新:

我尝试使用继承来隔离单个类中的建立连接语句,基于 rails doc 的解释,“此功能是通过在 ActiveRecord::Base 中保留一个连接池来实现的,该连接池是由该类索引的哈希。如果请求连接时,retrieve_connection 方法将上升到类层次结构,直到在连接池中找到连接。”。但是由于某种原因,rails 将 sqlite-connected 类的子类与默认的 mysql 连接相关联。所以我放弃了尝试与 sqlite 建立 has_many/belongs_to 关系,并对我的模型进行非规范化。

【问题讨论】:

    标签: ruby-on-rails ruby sqlite


    【解决方案1】:

    我认为“建立连接'sqlite'”引起了问题。尝试删除它。 SQLite 只允许一个连接用于写入每个数据库(一个文件)

    如果你对数据库执行多次写入而不关闭它,则会导致该异常

    Rails 可以自动高效地处理连接,所以我认为我们不需要单独建立连接。

    【讨论】:

    • 对,但是我如何将 sqlite db 配置与每个模型相关联(以区别于环境的默认 mysql 配置)?
    • 根据api.rubyonrails.org/classes/ActiveRecord/Base.html,它是自动调用的。作为一名 Rails 程序员,我从未在 ActiveRecord 模型中调用它
    • 所以澄清一下,我将 mysql 和 sqlite 数据库用于单个 rails 应用程序,并且我在一些类定义中调用了建立连接以将它们与 sqlite 数据库相关联。如果我省略这些语句,那么我看不到如何将这些模型类与 sqlite 相关联。
    【解决方案2】:

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

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

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

    无论如何,如 sqlite3 本身所述,预计会出现一些繁忙的异常。

    注意这种情况:sqlite busy

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

    如果您满足此条件,则超时不再有效。为避免这种情况,请不要将 select 放在 begin/commit 中。或使用独占锁开始/提交。

    希望这会有所帮助。 :)

    【讨论】:

      猜你喜欢
      • 2010-09-09
      • 2013-11-13
      • 2012-07-02
      • 1970-01-01
      • 2023-03-26
      • 2012-12-15
      • 1970-01-01
      • 2021-02-16
      • 2017-02-07
      相关资源
      最近更新 更多