拍卖/银行类应用程序中的乐观或悲观锁定(Rails / MySQL)
作者:互联网
我正在使用Rails 3.1和MySQL 5.1设计类似Web应用程序的拍卖.用户将拥有帐户余额,因此重要的是,如果某人资金不足,则不要竞标该拍卖品.
显然,我会将拍卖的“获胜”打包成交易,如下所示:
交易1:
ActiveRecord::Base.transaction do
a = Account.where(:id=>session[:user_id]).first
# now comes a long part of code with various calculations and other table updates, i.e. time pases
a.balance -= the_price_of_the_item
a.save!
end
顺便说一下,我目前正在使用开放式锁定,因此我的所有表都具有列lock_version.
在执行这样的交易时,用户可以通过另一个输入放置其他出价,因此,每当他们出价时,一段代码就会检查当前的可用余额是否足够
同样在这里:
交易2:
ActiveRecord::Base.transaction do
a = Account.where(:id=>session[:user_id]).first
raise ActiveRecord::Rollback if a.balance < the_price_of_the_bid + Bids.get_total_bid_value_for_user(session[:user_id])
# now process the bid saving
end
显然,我需要确保两个交易不重叠,否则交易2可能在交易1处于处理过程中时正在读取余额,而我最终账户余额为负(保存了投标,然后交易1提交了) ,则用户可能已经用他不再拥有的资金出价).
要注意的一件事是,交易2不会对帐户进行任何更改,它仅读取帐户.我想这可以归结为一个问题:如何在运行事务1时防止对选定的SELECT语句进行任何读取.
如何使事务2等待事务1完成?是否可以使用乐观锁定和可用的MySQL事务隔离级别之一,还是需要在这里使用悲观锁定?如果悲观锁定是唯一的答案
锁!
阅读完两次交易后的账户记录就足够了吗?
设计准则当然是
>我正在寻找性能最好的解决方案,即使这意味着更多
编码.
>数据一致性至关重要
解决方法:
现在已经花了将近10个小时不间断地使用Rails控制台阅读各种帖子和文档以及尝试和出错,我想总结一下我的发现:
乐观锁定:不能满足我的要求,只有当我实际保存帐户余额记录时,锁定才会生效.但是下标不会更新帐户记录,因此不会触发乐观锁定,除非我在帐户记录中保留一个字段,该字段跟踪所有未清出价的当前承诺资金,因此会在下标时更新帐户记录(我不想这样做,因为每当保存出价时都需要更新另一个数据库).
因此,仅保留悲观锁定.为了简单起见,我决定在User记录上加一个锁,因此事务1的代码更改为:
交易1:
ActiveRecord::Base.transaction do
u = User.find(session[:user_id],:lock=>true)
a = Account.where(:id=>session[:user_id]).first
a.balance -= the_price_of_the_item
... some more code here ...
a.save!
end
和交易2:
ActiveRecord::Base.transaction do
u = User.find(session[:user_id],:lock=>true)
raise ActiveRecord::Rollback if a.balance < the_price_of_the_bid + Bids.get_total_bid_value_for_user(session[:user_id])
# now process the bid saving
....
end
另外,我决定将MySQL事务隔离级别设置为SERIALIZABLE.
标签:ruby-on-rails-3-1,ruby-on-rails,mysql 来源: https://codeday.me/bug/20191201/2084485.html