場景如下:
用戶帳戶中有余額。當交易發生時,余額需要實時更新。如果這裏出現並發問題,就會造成用戶余額和實際交易的不壹致,這對公司和客戶都是非常危險的。
那麽如何避免:
網上查後,有兩種方式:
1,使用悲觀鎖
當需要更改余額時,通過代碼為當前需要更新的記錄在事務中設置forupdate行鎖,然後開始正常的查詢和更新操作。
這樣交易完成後才能操作其他交易。
當然要特別註意。如果您使用Spring的事務註釋,您需要配置它:
class="org..jdbc.datasource。
在指定代碼處添加交易註釋。
@
@覆蓋
publicboolean(LonguserId,BigDecimalamount)
投擲{
longtime =系統。();
//獲取記錄上的鎖
UserBalancebalance=。getLock(userId);
logger . info("[lock]start . time:{ } ",time);
if(null==balance){
thrownew(
。ERRORCODE_BALANCE_NOTEXIST," uselbalancesinotexist ");
}
booleanresult=。(余額,金額);
longtimeEnd=System。();
LOGGER.info("[lock]end.time:{} ",time end);
返回結果;
}
實際測試可以有效控制MyBatis中的鎖定模式,但在大並發的情況下可能會出現性能問題。
select * from user _ balance where id = # { id,jdbcType = BIGINT } forupdate
]]
2.使用樂觀鎖定
這種方法也可以解決場景中描述的問題(我覺得更適合不頻繁的操作):
設計表格時,會添加壹個版本(版本控制字段)。每次需要更新余額時,先獲取對象。更新時,根據版本和id進行更新。如果更新次數為0,則版本已經更改。
您需要如下重復更新操作:sql腳本
update user _ balancesetBalance = # { balance,jdbcType=DECIMAL},Version = Version 1其中Id=#{id,jdbcType=BIGINT}和Version=#{version,JDBC type = BIGINT }
這是壹種不使用數據庫鎖的方法,解決方案也很巧妙。當然,在大量並發的情況下,壹次推演需要重復多次才能成功,還是有不足之處的。不知道有沒有更好的辦法。