【问题标题】:Ensuring a transaction within a method with ActiveRecord使用 ActiveRecord 确保方法内的事务
【发布时间】:2013-09-29 09:41:38
【问题描述】:

我有一种情况,我想要一种方法在事务中工作,但前提是事务尚未启动。这是一个人为的例子来提炼我在说什么:

class ConductBusinessLogic
  def initialize(params)
    @params = params
  end

  def process!
    ActiveRecord::Base.transaction do
      ModelA.create_multiple(params[:model_a])
      ModelB.create_multiple(params[:model_a])
    end
  end
end

class ModelA < ActiveRecord::Base
  def self.create_multiple(params)
    # I'd like the below to be more like "ensure_transaction"
    ActiveRecord::Base.transaction do
      params.each { |p| create(p) }
    end
  end
end

class ModelB < ActiveRecord::Base
  def self.create_multiple(params)
    # Again, a transaction here is only necessary if one has not already been started
    ActiveRecord::Base.transaction do
      params.each { |p| create(p) }
    end
  end
end

基本上,我不希望这些充当嵌套事务。我希望.create_multiple 方法仅在尚未在事务中调用它们的情况下启动事务,例如通过ConductBusinessLogic#process!。如果模型方法被自己调用,它们应该启动自己的事务,但如果它们已经在事务内部被调用,如通过ConductBusinessLogic#process!,它们不应该嵌套子事务。

我不知道 Rails 提供这种开箱即用的方式。如果我按原样运行上面的代码并且由模型方法之一触发回滚,则整个事务仍将通过,因为子事务吞下了ActiveRecord::Rollback 异常。如果我在子事务上使用requires_new 选项,保存点将用于模拟嵌套事务,并且实际上只有那个子事务会被回滚。我想要的行为将是ActiveRecord::Base.ensure_transaction 的效果,这样只有在没有外部事务时才启动新事务,以便任何子事务都可以触发整个外部事务的回滚。这将允许这些方法自己进行事务处理,但如果有父事务,则遵从父事务。

是否有实现此行为的内置方法,如果没有,是否有可以工作的 gem 或补丁?

【问题讨论】:

标签: ruby-on-rails transactions rails-activerecord


【解决方案1】:

ModelAModelB 类中添加一个create_multiple_without_transaction 方法怎么样?看起来像这样:

class ConductBusinessLogic
  def initialize(params)
    @params = params
  end

  def process!
    ActiveRecord::Base.transaction do
      ModelA.create_multiple_without_transaction(params[:model_a])
      ModelB.create_multiple_without_transaction(params[:model_a])
    end
  end
end

class ModelA < ActiveRecord::Base
  def self.create_multiple(params)
    # I'd like the below to be more like "ensure_transaction"
    ActiveRecord::Base.transaction do
      self.create_multiple_without_transaction(params)
    end
  end

  def self.create_multiple_without_transaction(params)
    params.each { |p| create(p) }
  end
end

那么您的常规 create_multiple 将像以前一样工作,但如果您不需要交易,您只需致电 create_multiple_without_transaction

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-01
    • 2011-05-28
    • 1970-01-01
    • 2021-06-25
    • 1970-01-01
    • 1970-01-01
    • 2016-12-06
    相关资源
    最近更新 更多