繁体   English   中英

活动记录中的交易

[英]transaction in activerecord

民间,

我对Rails中的activerecord中的事务还很陌生,并且我有一段代码,在其中执行以下操作:

transaction do
  specimen = Specimen.find_by_doc_id(25)
  specimen.state = "checking"
  specimen.save
  result = Inventory.do_check(specimen)
  if result
    specimen.state="PASS"
  else
    specimen.state="FAIL"
  end
  specimen.save
end

我在这里使用事务的目标是,如果我在Inventory.do_check中得到一个异常(它是外部Web服务的客户端,并且执行一堆HTTP调用和检查),那么我希望sample.state回滚到其先前的值。 我想知道这样是否可以正常工作? 同样,在我的开发机器上,锁似乎是在整个“标本”表上设置的,当我尝试查询该表/模型时,我遇到了“忙”异常(我正在使用SQLLite)。 我以为只能在该对象/记录上设置锁定。

非常感谢任何反馈,因为我说过我真的很陌生,所以我的问题可能很幼稚。

实现和锁定取决于数据库。 我不使用SQLLite,并且在这种情况下锁定整个表也不会感到惊讶。 但是读取仍然可以工作,因此可能是因为它不允许在单个连接上执行两个并发操作,因此在允许任何其他操作之前等待事务完成。 例如,请参见以下SO答案: https : //stackoverflow.com/a/7154699/2117020

但是,我的主要观点是,无论如何在访问外部服务时都不应该暂停事务。 不管它实现了多少秒,这都不是您想要的。 在您的情况下,看起来您想要的只是从异常中恢复。 您是否只是想将状态设置为“失败”或“初始”,还是do_check()修改了样品? 如果do_check()不修改样本,则最好执行以下操作:

specimen = Specimen.find_by_doc_id(25)
specimen.state="checking"
specimen.save
# or simply specimen.update_attribute( :state, "checking" )

begin
  specimen.state = Inventory.do_check(specimen) ? "PASS" : "FAIL"
rescue
  specimen.state = "FAIL" # or "initial" or whatever
end
specimen.save

锁定将高度依赖于您的数据库。 您可以使用行锁。 像这样:

specimen = Specimen.find_by_doc_id(25)

success = true

# reloads the record and does a select for update which locks the row until the block exits (its wrapped in a transation)
specimen.with_lock do
  result = Inventory.do_check(specimen)
  if(result)
    specimen.state="PASS"
  else
    specimen.state="FAIL"
  end
  specimen.save!
end

检查事务中的外部站点并不理想,但是如果使用with_lock并且数据库支持行锁,则应该仅锁定此单行(它将阻止读取,因此请谨慎使用)

查看活动记录中的悲观锁定文档: http : //ruby-docs.com/docs/ruby_1.9.3-rails_3.2.2/Rails%203.2.2/classes/ActiveRecord/Locking/Pessimistic.html

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM