2014-11-04 34 views
0

说我有连接到另一个数据库模型:与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决定是否应该换一个SQL语句BEGINCOMMIT(貌似ActiveRecord的不会刻意去检查,如果模型1和模型2被连接到同一个数据库),并有一个更好的解决方法在这里?

回答

0

原来的解决方案是非常简单的(答案是正确的的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,那么每个类都有自己的连接池,这会浪费资源,并且会在我的问题中提到事务问题。