2010-06-29 41 views
1

我需要执行导轨某些原子的算术,但我发现这样做对单个对象的唯一途径是通过原油update_all类方法,如:原子算术

Account.update_all(["debits = debits + ?", amount], :id => id) 

随着收藏协会,该update_all类方法应该是可用作关联方法,因为收藏品将通过失踪方法调用的类的相关范围:

accounts.update_all(["debits = debits + ?", amount]) 

当收集处理,这是好多了,并重新少petitive。然而,这不适用于单身人士协会,即belongs_tohas_one。对于AssociationProxymethod_missing传递给目标实例,实例方法(自然)不会有update_all实例方法。

是否有更优雅的方式来执行此算术?或者是update_all尽可能好?

+0

我有点糊涂 - 如果你要更新单个记录,为什么不直接实例化一个对象,改变它,并保存为正常? 还有.update方法,但我不确定它会执行你正在尝试的操作。 – adriandz 2010-06-29 03:52:43

+1

因为这不是原子的。有一个窗口可能会丢失数据。换句话说,一个竞赛条件。 如果进程A从数据库读取值,然后进程B对其进行修改,则进程A将对旧值执行其算术运算。当进程A将其新计算值保存回数据库时,进程B所做的更改将丢失。 Rails提供的'increment!'方法有这个问题。它不是原子的,因为它从数据库读取数据,在Ruby中计算新值,然后写入数据库。 – Ian 2010-06-29 06:00:52

+0

这是你在找什么? http://stackoverflow.com/questions/4872772/can-i-do-an-atomic-increment-in-rails-2-3-without-dropping-down-to-sql/8225945#8225945 – Josh 2011-11-22 11:22:05

回答

0

你不打算在长时间内在大量记录上击败update_all的表现。任何理由不使用它并将其包装在交易中?

+0

因为(至少在MySQL中)在单个查询中执行的算术将是原子的,所以不需要将其包装在事务中。这就是为什么我首先在​​'update_attribute'上选择'update_all'的原因。正如我所说:它的工作原理与我写的一样,但我正在寻找一种更优雅的方式。 而且这不是我关心的集合,所以性能不是问题。通过关联访问'update_all'方法对于我的口味来说已经足够优雅了,因为它可以使我无需对范围进行硬编码。它是我想要清理并制作更多DRY的标量对象和关联的更新。 – Ian 2010-06-30 02:54:26