数据库
首页 > 数据库> > 拍卖/银行类应用程序中的乐观或悲观锁定(Rails / MySQL)

拍卖/银行类应用程序中的乐观或悲观锁定(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