mysql - ActiveRecord 的分布式事务边界

标签 mysql ruby-on-rails activerecord transactions

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

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)

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 共享同一个连接池。如果在每个类中都调用external_connection,那么每个类都会有自己的连接池,这样会浪费资源,并且会出现我问题中提到的事务问题。

关于mysql - ActiveRecord 的分布式事务边界,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26731316/

相关文章:

mysql - Rails 独特的约束模型 + 数据库级别和竞争条件

php - 哪个 PHP 框架最接近于 ActiveRecord (RoR)

java - 如何获取结果集中WHERE条件求值的结果?

c++ - mysql C++ 从所有列中选择所有行

ruby-on-rails - 更新到 Ruby 2.0 打破了我的 Assets 管道

ruby-on-rails - json erb模板找不到其他html部分

php - Codeigniter 从 table1 获取具有 table2 id 的名称列表

mysql - 返回多列的自定义函数

ruby-on-rails - 闪光[:notice] displaying extra character

ruby-on-rails - 使用 Arel 按频率排序记录