首页 文章

ActiveRecord,Sqlite3和BusyException

提问于
浏览 373
1

我有一个配置了混合mysql和sqlite3数据库连接的rails应用程序,并且为了将特定模型与sqlite3相关联,我在每个类定义中添加了“establish_connection'sqlite_db_config_name'”行 .

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

我假设有一种方法可以使这项工作,我正在使用不正确的connect_connection .

其他人遇到这个吗?

database.yml config:

开发:

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

更新:

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

2 回答

  • 1

    我认为“establish_connection'sqlite”会导致问题 . 尝试删除它 . SQLite只允许一个连接来写每个数据库(一个文件)

    如果在不关闭数据库的情况下对数据库执行多次写入操作,则会导致该异常

    Rails可以有效且自动地处理连接,因此我认为我们不需要单独 Build 连接 .

  • 0

    我在sqlite3 ruby扩展程序上发现了一个死锁,并在此处修复它:继续使用它,看看这是否解决了你的问题 .

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

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

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

    Be aware 有这种情况:sqlite busy

    The presence of a busy handler does not guarantee that it will be invoked when there is 
        lock contention. If SQLite determines that invoking the busy handler could result in a 
        deadlock, it will go ahead and return SQLITE_BUSY or SQLITE_IOERR_BLOCKED instead of 
        invoking the busy handler. Consider a scenario where one process is holding a read lock 
        that it is trying to promote to a reserved lock and a second process is holding a reserved 
        lock that it is trying to promote to an exclusive lock. The first process cannot proceed 
        because it is blocked by the second and the second process cannot proceed because it is 
        blocked by the first. If both processes invoke the busy handlers, neither will make any 
        progress. Therefore, SQLite returns SQLITE_BUSY for the first process, hoping that this 
        will induce the first process to release its read lock and allow the second process to 
        proceed.
    

    如果您满足此条件,超时将不再有效 . 要避免它,请不要将select放在begin / commit中 . 或者使用独占锁来开始/提交 .

    希望这可以帮助 . :)

相关问题