繁体   English   中英

为什么此事务在ActiveRecord中不起作用?

[英]Why does this transaction not work in ActiveRecord?

我目前正在玩交易,无法绕过以下场景:

鉴于存在用户名为“johnny”且全名为“John Smith”的用户。

我启动两个rails控制台并按此顺序执行以下命令:

控制台A:

ActiveRecord::Base.transaction { user = User.find_by_username("foo"); sleep 10; user.update_attribute(:full_name, "#{user.full_name}-1"); }

控制台B:

ActiveRecord::Base.transaction { user = User.find_by_username("foo"); sleep 10; user.update_attribute(:full_name, "#{user.full_name}-2"); }

所以时间如下:

读“约翰史密斯”

B读“约翰史密斯”

写道“John Smith-1”

B写道“John Smith-2”

根据我的数据库类事务,B应该无法编写“John Smith-2”,因为数据自读取后就已更改。 因此,交易应该回滚,交易A应该赢。 我希望用户名是“John Smith-1”,但结果是“John Smith-2”。

任何想法为什么会发生这种情况或如何获得预期的行为?

亲切的问候

尼尔斯

据我所知,事务不是关于锁定,事务的主要目的是确保原子的变化。 例如,当您从支票账户中扣除资金并将其存入储蓄账户时,您需要确保INSERT成功或两者都失败,否则您将处于不一致状态。 您需要的是锁定,例如http://api.rubyonrails.org/classes/ActiveRecord/Locking/Optimistic.html

更新:根据我的理解,ACID并不意味着回滚事务。 如果没有错误,则两个事务都将成功。 你得到的结果取决于隔离。 如果使用SERIALIZABLE级别,您将获得“John Smith-1-2”,但InnoDB默认使用REPEATABLE READ级别http://dev.mysql.com/doc/refman/5.0/en/set-transaction.html #isilevel_repeatable-read ,这意味着如果SELECT是非锁定的( User.find_by... ),它将不会锁定记录以进行读取,并且您从事务A启动时创建的快照中获得原始结果(即从B中SELECT直到A完成后才会锁定,如同SERIALIZABLE )。

更新:同时您可以查看http://api.rubyonrails.org/classes/ActiveRecord/Locking/Pessimistic.html以获得悲观锁定。

暂无
暂无

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

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