繁体   English   中英

带有ActiveRecord的分布式事务边界

[英]Distributed transaction boundary with ActiveRecord

假设我有连接到另一个数据库的模型:

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如何决定是否应该使用BEGINCOMMIT包装SQL语句(看起来activerecord不会费心检查Model1和Model2是否连接到同一数据库),并且这里有更好的解决方法吗?

事实证明,解决方案非常简单(答案就在ActiveRecord :: Base文档中,我完全是盲目的)

开设课程

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

然后Model1Model2只需要继承Database2 ,一切就可以正常进行。

万一有人怀疑,以这种方式, Model1Model2共享相同的连接池。 如果调用establish_connection在每类中,那么每个班级都会有自己的连接池,浪费资源,而且会在我的问题中提及的交易问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM