假设我有连接到另一个数据库的模型:
class Model1 < ActiveRecord::Base
establish_connection {config_to_connection_to_database2}
end
class Model2 < ActiveRecord::Base
establish_connection {config_to_connection_to_database2}
end
当我开始交易时,说
Model1.transaction do
Model1.create! something
Model2.create! something
#some other thing
end
生成的SQL是:
BEGIN
INSERT INTO model1 ...
BEGIN
INSERT INTO model2 ...
COMMIT
#some other thing might happen here
COMMIT
当#some other thing
中发生错误时,INSERT INTO model2
不会回滚,因为它位于嵌套事务中并且已经提交,而 INSERT INTO model1
已回滚。
我发现了一个丑陋的解决方法:
Model1.transaction do
Model2.transaction do
Model1.create! something
Model2.create! something
#some other thing
end
end
SQL 变为:
BEGIN
BEGIN
INSERT INTO model1 ...
INSERT INTO model2 ...
#some other thing might happen here
COMMIT
COMMIT
这有效,但对我来说有点烦人。
所以我的问题是:activerecord如何决定是否应该用BEGIN
和COMMIT
包装SQL语句(看起来activerecord不会费心检查Model1和Model2 连接到同一个数据库),这里有更好的解决方法吗?
最佳答案
事实证明解决方案非常简单(答案就在 ActiveRecord::Base 文档中,我完全失明了)
开设类(class)
class Database2 < ActiveRecord::Base
self.abstract_class = true #this is important, otherwise the inherited class's table name would be 'database2'
establish_connection your_connection_config
end
然后Model1
和Model2
只需要继承Database2
,一切就可以正常工作了。
万一有人想知道,这样,Model1
和 Model2
共享同一个连接池。如果在每个类中都调用external_connection
,那么每个类都会有自己的连接池,这样会浪费资源,并且会出现我问题中提到的事务问题。
关于mysql - ActiveRecord 的分布式事务边界,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26731316/