如何从ActiveRecord中的事务中排除模型?
我有一个特殊情况模型,它不能成为外部事务的一部分:
Outer.Transaction do ... Inner.create(:blah) ... end
我如何阻止Inner成为交易的一部分,假设Inner不知道它将被拉入哪个特定交易?
例如,创建内部事务是不行的,因为它也将成为外部事务的一部分。
我想这样做是因为内部模型需要立即写入而不是等待外部事务提交。
我很好奇什么需要这样的结构!
我认为,如你所描述的那样,如果没有一点ha,就会很难做到这一点。 例如,您可以在mysql中将Inner
的表存储类型设置为不支持事务的表(MyIsam eg),同时保持其他类的表存储具有支持事务的内容(YUK!)。
如果可以的话,在交易Inner.create
之前,你几乎肯定会更好地推迟Inner.create
。 您可以使用begin with ensure确保始终发生创建。 就像是:
create_inner = false begin Outer.transaction.do ... create_inner = true # instead of Inner.create(:blah) ... end ensure if create_inner Inner.create(:blah) end end
如果块的其余部分依赖于创建的Inner
实例,这将变得更加复杂。 您可以在块中创建实例,并在块的末尾将created_inner
设置为false,这样,如果代码运行无例外,它将在事务中创建,您将不会再次在ensure中创建。
如果你想在一般情况下这样做,你可以在Inner
上定义一个类方法来执行一个块但总是创建一个Inner
对象。 您还需要将一个after_create
添加到Inner
。 您可以依赖块中的Inner.create
调用在事务成功时创建它,但如果它被回滚,那么您需要在之后创建它。 例如:
class Inner < ActiveRecord::Base def self.ensure_created(&block) Thread.current[:created_inner] = false begin block.call rescue => e if Thread.current[:created_inner] Inner.create(:blah) end raise e end end def after_create # Flag that an instance has been created in this thread so # that if we rollback out of a transaction we can create again Thread.current[:created_inner] = true end
然后你会这样称呼它:
Inner.ensure_created do Outer.transaction do ... Inner.create(:blah) ... end end
但是,这种方法存在很多缺点,我不确定我是否会提倡这种方法。 这很复杂。 如果引发ActiveRecord :: Rollback,它将无效,因为该exception不会从Outer.transaction
但会导致不创建Inner
实例。 嵌套两个或多个调用时,它将无法正常工作。 最后我还没有彻底测试过 – 请谨慎使用!
您可以为Inner定义单独的数据库连接,然后该事务将仅应用于Outer的连接。
- 如何在具有名为“valid”的列的数据库上使用ActiveRecord? (DangerousAttributeError)
- ruby on rails 3使用缓存数据重新加载
- Ruby on Rails:有没有办法从数据库中提取项目并按指定顺序返回它们?
- 重命名ActiveRecord / Rails的created_at,updated_at列
- Rails first_or_create中的竞争条件
- 无法访问块中的ActiveRecord mutators
- rails 4中的“find_all_by_id”等价物
- 从范围记录计算总数百分比并显示虚拟属性(Rails / Active Record)
- Rails 4 MySQL bigInt主键问题和错误