Ruby on rails ActiveRecord:验证和写入数据库之间的并发访问

Ruby on rails ActiveRecord:验证和写入数据库之间的并发访问,ruby-on-rails,database,ruby-on-rails-3,activerecord,transactions,Ruby On Rails,Database,Ruby On Rails 3,Activerecord,Transactions,假设我有一个在线书店,其数据模型如下所示: 在创建新订单之前,我想确保有足够的商品在库存中,所以我有这样一种方法 def ensure_enough_in_stock errors.add(:quantity, "not enough in stock") if quantity > book.stock end 为了确保在保存到数据库之前调用此方法,我使用验证: validate :ensure_enough_in_stock, :on => create 总之,当我

假设我有一个在线书店,其数据模型如下所示:

在创建新订单之前,我想确保有足够的商品在库存中,所以我有这样一种方法

def ensure_enough_in_stock
    errors.add(:quantity, "not enough in stock") if quantity > book.stock
end
为了确保在保存到数据库之前调用此方法,我使用验证:

validate :ensure_enough_in_stock, :on => create
总之,当我创建订单时:

  • 验证方法被称为
  • 新订单将写入数据库(如果验证通过)
  • 如果介于1之间,会发生什么情况。另一个进程(并发访问,另一个线程,…)对同一本书的stock属性进行修改?是否提出了例外情况

    一般来说,如何处理在验证和将保存到数据库之间发生的情况

    我认为我也应该在数据库中进行验证,但我不知道它会对性能产生什么影响。有没有一个聪明的方法来处理这种情况

    编辑

    如前所述锁定交易会阻止对股票的写访问,但如果我在图书模型中也有一个“published”属性,该属性的值可以是“public”或“private”,那么会发生什么呢?我想确保你不能购买一本私人图书

    但是,正如股票价值可以通过外部过程改变一样,公布的价值也可以改变:在这种情况下,锁定没有任何帮助,不是吗


    Rails通常在事务中包装验证和保存。因此,您需要做的唯一一件事就是使用lock-in
    运行查询,确保库存充足。锁将防止数据被其他请求更改。有关如何使用锁进行查询,请参阅。

    对于MySQL,“如果使用使用页锁或行锁的存储引擎进行更新,则查询检查的行将被写锁定,直到当前事务结束。”()因此,在当前事务期间,没有进程能够更新记录。在您的情况下,库存、已发布或任何其他字段都不会更改,即使是通过外部流程。