【发布时间】:2012-11-07 11:45:58
【问题描述】:
假设我在网上书店的数据模型看起来像这样:
在创建新订单之前,我想确保有足够的商品库存,所以我有这样的方法
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. 和 2. 之间,另一个进程(一个并发访问,另一个线程,...)对同一本书的 stock 属性进行了修改,会发生什么?是否引发异常?
更一般地说,如何处理在验证和保存到数据库之间发生的情况?
我认为我也应该在数据库中进行验证,但我不知道它会对性能产生什么影响。有没有巧妙的办法来处理这种情况?
编辑
按照here 的说明锁定交易可以防止对股票的写访问,但是如果我在 Book 模型中也有一个“已发布”属性会发生什么情况,该属性可以取值“公共”或“私有”,然后我想确保您不能购买私人书籍。
但与股票值可以通过外部进程更改相同的方式,发布的值也可以更改:在这种情况下,锁定不会有任何帮助,不是吗?
【问题讨论】:
-
对于 MySQL,“如果您将 FOR UPDATE 与使用页或行锁的存储引擎一起使用,则查询检查的行将被写锁定,直到当前事务结束。” (dev.mysql.com/doc/refman/5.0/en/select.html) 因此,在当前事务期间,没有进程能够更新记录。在您的情况下,stock、published 或任何其他字段都不会更改,即使通过外部流程也是如此。
标签: ruby-on-rails database ruby-on-rails-3 activerecord transactions