在`before_save`和`save`之间的ActiveRecord和transactions

时间:2010-04-16 09:41:16

标签: ruby activerecord locking

我在before_save中有一些逻辑,其中(仅)在满足某些条件时,我创建新行,special_number等于数据库中的最大special_number + 1.(如果条件不满足然后我做一些不同的事情,所以我不能使用自动增量)

我担心的是,如果在第一个保存时执行第二个线程,则同时作用于此数据库的两个线程可能会选择相同的special_number。有没有办法在before_save和完成保存之间锁定数据库,但只在某些情况下?我知道所有保存都是在交易中发送的,这会为我做这个工作吗?

def before_save
  if things_are_just_right
    # -- Issue some kind of lock?
    # -- self.lock? I have no idea
    # Pick new special_number
    new_special = self.class.maximum('special_number') + 1
    write_attribute('special_number',new_special)
  else
    # No need to lock in this case
    write_attribute('special_number',some_other_number)
  end
end

1 个答案:

答案 0 :(得分:1)

如果特殊数字总是增加1,并且您无法获得“间隙”,并且它已保存在数据库中 - 您可以使用select for update:

SELECT special_num FROM nums FOR UPDATE;
UPDATE nums SET special_num  = special_num  + 1;

您可以在此处阅读:select for update

请注意,它正在锁定数据库,因此如果您对特殊号码进行了大量更新,则可能会出现性能问题。

如果您不介意在特殊数字中存在间隙(如果事务失败),一种简单的方法是使用memcahced“inc”函数,因为它将非常非常快地执行:)