我有一个配置了混合mysql和sqlite3数据库连接的rails应用程序,并且为了将特定模型与sqlite3相关联,我在每个类定义中添加了“establish_connection'sqlite_db_config_name”行。
当我尝试单独保存任何sqlite3连接的模型对象时,保存成功,但是当我尝试保存由其他对象组成的对象时(通过has_many),我得到一个BusyException。我有一种感觉,因为每个对象都有自己的数据库连接,顶级对象锁定数据库然后调用成员对象的保存方法,他们无法获取锁。
我假设有一种方法可以完成这项工作,而且我正在使用不正确的connect_connection。
其他人遇到过这个吗?
database.yml config:
dev的:
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关系,并对我的模型进行了规范化。
答案 0 :(得分:1)
我认为“establish_connection'sqlite”会导致问题。尝试删除它。 SQLite只允许一个连接用于写入每个数据库(文件)
如果对数据库执行多次写操作而不关闭它,则会导致该异常
Rails可以高效自动地处理连接,因此我认为我们不需要单独建立连接。
答案 1 :(得分:0)
我在sqlite3 ruby扩展程序上发现了一个死锁,并在此处修复它:继续使用它,看看这是否解决了你的问题。
https://github.com/dxj19831029/sqlite3-ruby
我打开了一个拉取请求,没有他们的回复。
无论如何,如sqlite3本身所述,预计会有一些繁忙的异常。
请注意此条件: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中。或者使用独占锁来开始/提交。
希望这会有所帮助。 :)