
典型冪等策略

唯一索引策略(極少使用)
1.select+insert+唯一索引沖突
//1.根據(jù)冪等號(hào)查詢(xún)冪等記錄
Record record = dao.select(param);
if (record != null){
//2.冪等記錄存在,直接返回冪等結(jié)果或根據(jù)記錄狀態(tài)(如失敗可重試)進(jìn)一步處理
}else{
try{
//3.冪等記錄不存在,插入冪等記錄
dao.insert(entity);
//4.插入成功,執(zhí)行業(yè)務(wù)邏輯
}catch(DuplicateKeyException e){
//5/插入失敗,若為重復(fù)異常,直接返回冪等結(jié)果或進(jìn)一步處理
record = dao.select(param);
//6.處理邏輯
}catch(Throwable tr){
//7.其他異常處理邏輯
}
}
2.insert+唯一索引沖突
//1.插入冪等記錄
try{
//2.插入成功,執(zhí)行業(yè)務(wù)邏輯
dao.insert(entity);
}catch(DuplicateKeyException e){
//3.插入失敗且為重復(fù)異常,直接返回冪等結(jié)果或進(jìn)一步處理
dao.select(param);
//4.處理邏輯
}catch(Throwable tr){
//5.其他異常處理邏輯
}
數(shù)據(jù)庫(kù)開(kāi)銷(xiāo)大,如果重復(fù)請(qǐng)求發(fā)生的概率較小,可優(yōu)先選擇2.insert+唯一索引沖突。
唯一索引需結(jié)合冪等記錄狀態(tài)變更管控+事務(wù)機(jī)制(數(shù)據(jù)庫(kù)事務(wù)/分布式事務(wù))+鎖機(jī)制。
悲觀鎖策略(金融賬務(wù)清算域常用方式)
//1.開(kāi)啟事務(wù)
begin;
//2.基于冪等號(hào) biz_no 鎖行查詢(xún)
record = select * from table_name where biz_no='xxxx' for update
//3.沒(méi)有相關(guān)冪等記錄,說(shuō)明是首次請(qǐng)求
if (record == null){
//4.初始化并插入冪等記錄
insert(init(param))
//5.再次基于冪等號(hào)biz_no鎖行查詢(xún)
record = select * from table_name where biz_no='xxxx' for update
}
//6.鎖行查詢(xún)成功,根據(jù)記錄判斷決策處理方式
if (record.getStatus() != 預(yù)期狀態(tài)){
//7.非預(yù)期狀態(tài),結(jié)束處理
return;
}
//8.預(yù)期狀態(tài),執(zhí)行業(yè)務(wù)邏輯,如查詢(xún),更新流水等
//9.更新記錄
update table_name set status ='目標(biāo)狀態(tài)' where biz_no='xxx';
//10.提交事務(wù)
commit
通過(guò)串性化實(shí)現(xiàn)冪等,資源占用較多
依靠數(shù)據(jù)庫(kù)自身的特性來(lái)實(shí)現(xiàn),實(shí)現(xiàn)成本低,結(jié)合了事務(wù)機(jī)制保障了較強(qiáng)的數(shù)據(jù)一致性,解決了請(qǐng)求并發(fā)、亂序等的問(wèn)題
1.查詢(xún)冪等數(shù)據(jù)的狀態(tài),如果是不可重試終態(tài),直接返回;
2.如果是可重試終態(tài),則進(jìn)行重試(同一冪等號(hào)),涉及到下游則需要結(jié)合分布式事務(wù)
3.插入冪等記錄TransactionTemplate REQUIRED_NEW
4.下游處理成功,則變更冪等記錄狀態(tài)
5.下游也必須是冪等的。
分布式鎖

SETNX keyName value,若keyName已存在于Redis中,則返回0;
若不存在,則返回1.
//1.嘗試將keyName寫(xiě)入緩存
if(redis.setNx(keyName, 1) == 1){
//2.寫(xiě)入成功,即獲取鎖成功,繼續(xù)執(zhí)行業(yè)務(wù)邏輯
//3.執(zhí)行完成,釋放鎖(為了防止誤釋放,可采用LUA腳本)
}else{
//4.寫(xiě)入失敗,即獲取鎖失敗,要么直接返回,要么等待、重試
}
需結(jié)合事務(wù)機(jī)制和重試機(jī)制形成完整方案。
事務(wù)機(jī)制用于保證業(yè)務(wù)邏輯的數(shù)據(jù)一致性;重試機(jī)制是基于持久化的冪等記錄進(jìn)行失敗重試,保證最終一致性。
還存在釋放鎖操作可能失敗的情況。一旦釋放鎖操作失敗,就會(huì)導(dǎo)致一段時(shí)間內(nèi)記錄一直在緩沖中,其他線程無(wú)法獲得鎖。
即使設(shè)置了失效時(shí)間,在有效期內(nèi)仍會(huì)存在問(wèn)題。失效時(shí)間過(guò)短,業(yè)務(wù)邏輯執(zhí)行完前釋放鎖,失效時(shí)間過(guò)長(zhǎng),其他嘗試獲取鎖的過(guò)程就需要等待,甚至可能超時(shí)。
解決冪等問(wèn)題的關(guān)鍵
- 1.唯一性約束
- 2.執(zhí)行唯一性檢查
解決冪等問(wèn)題的實(shí)現(xiàn)方式
唯一索引:數(shù)據(jù)庫(kù)唯一索引,唯一索引可以基于業(yè)務(wù)流水建立,也可以單獨(dú)建表實(shí)現(xiàn);
唯一數(shù)據(jù):悲觀鎖、樂(lè)觀鎖、分布式鎖等鎖機(jī)制;
狀態(tài)機(jī)約束:對(duì)于存在狀態(tài)流轉(zhuǎn)的業(yè)務(wù),通過(guò)狀態(tài)機(jī)的流轉(zhuǎn)約束,可以實(shí)現(xiàn)有限狀態(tài)機(jī)的冪等。