【问题标题】:Rails Save a record within transaction even if transaction rolls back?Rails 即使事务回滚,也要在事务中保存记录?
【发布时间】:2012-07-13 18:05:43
【问题描述】:

我有一系列记录要保存为交易的一部分。除了正常的 AR 记录外,我还在进行信用卡网关交易。如果它或 AR 交易失败,我希望一切都回滚……除了我从信用卡网关返回的失败交易的数据(原因、日期等)。类似的东西

def pay
  Payment.transaction do
    payment.save
    other.save
    result = credit_card.purchase  # this does the gateway transaction, no database stuff
    if result.failure
      raise ActiveRecord::Rollback
      result.save  # this is the part I want to always save
    end
    another.save
  end
end

有没有办法从失败回滚中排除事务中的特定部分?

Rails 3.2.5,MySQL 5.1

【问题讨论】:

    标签: ruby-on-rails-3 transactions


    【解决方案1】:

    我不是 100% 确定我理解你为什么要这样做,但你能把信用卡的东西保存在交易之外吗?

    result = nil
    Payment.transaction do
      payment.save
      other.save
      result = credit_card.purchase  # this does the gateway transaction, no database stuff
      if result.failure
        raise ActiveRecord::Rollback      
      end
    end
    result.save
    

    (由于块变量作用域的工作方式,您需要在事务之前将结果设置为 nil)

    另一种可能的策略是利用事务是在每个连接的基础上完成的这一事实。两个线程将使用不同的连接,所以你可以这样做:

    Payment.transaction do
      payment.save
      other.save
      result = Thread.new do
        ActiveRecord::Base.connection_pool.with_connection do
          credit_card.purchase.tap do |result|
            result.save
          end
        end
      end.join.value
      if result.failure 
        raise ActiveRecord::Rollback
      end
    end
    

    或者只是:

    Payment.transaction do
      payment.save
      other.save
      result = credit_card.purchase
      Thread.new do
        ActiveRecord::Base.connection_pool.with_connection do
          result.save
        end
      end.join
      if result.failure 
        raise ActiveRecord::Rollback
      end
    end
    

    这里的购买发生在另一个线程上,即使用它自己的数据库连接。该线程中发生的任何事情都不会回滚

    【讨论】:

    • 噢!是的,在交易之外保存 cc 结果可能是我想要的。有时,显而易见的答案对我来说并不明显。线程技巧很整洁;我在多个连接的文档中看到了警告,但并没有飞跃性地利用它来发挥我的优势......虽然有点hacky,因为它似乎是实现的工件而不是有意的机制。无论如何,很棒的答案-谢谢。
    • 有用!小修正:结果将是一个死线程。要得到结果: result = nil Thread.new(result) do |result| ActiveRecord::Base.connection_pool.with_connection do result = credit_card.purchase end end.join
    • 更新为添加 .join。看起来第二个示例也缺少 result.save 所以也添加了。没有测试代码,所以希望它是正确的......
    猜你喜欢
    • 1970-01-01
    • 2015-04-23
    • 1970-01-01
    • 2013-01-17
    • 2013-12-15
    • 1970-01-01
    • 1970-01-01
    • 2016-04-16
    相关资源
    最近更新 更多