tl;dr
通過唯一編號確定同一請求,沒有唯一編號的自行生成。
資料庫記錄操作狀態,資料庫事務保證資料一致性。
概述通過http api進行通訊的系統,在支付或者只允許操作一次的相關場景中,對介面的冪等性有嚴格要求。
介面的冪等性體現在:
請求執行成功所得到的結果與次數無關
如果介面沒有實現冪等性,對於轉賬的應用場景:
a. 正常轉賬
a賬戶金額為¥200,b賬戶金額¥100
a呼叫api向b轉賬¥100,介面呼叫成功
a賬戶金額為¥100,b賬戶金額¥200
在這一場景下,整個流程正常,介面無論是否實現冪等性與否都對執行結果沒有影響。
b. 轉賬重試
a賬戶金額為¥200,b賬戶金額¥100
a呼叫api向b轉賬¥100,介面呼叫失敗
a重試請求,本次成功
a賬戶金額為¥100,b賬戶金額¥200
在這一場景,重試成功的情況下,介面無論是否實現冪等性與否都對執行結果沒有影響。
c. 轉賬操作超時後重試
a賬戶金額為¥200,b賬戶金額¥100
a呼叫api向b轉賬¥100,介面呼叫超時,a不了解本次轉賬是否完成,服務端實際轉賬成功
a重試請求,本次成功
a賬戶金額為¥0,b賬戶金額¥300
在實際應用場景中,介面超時的情況並不罕見,介面超時不代表操作失敗,可能存在的情況就有操作實際成功然而並沒有返回資料。在這樣乙個場景之下,介面沒有實現冪等性造成重複操作,對於系統的可靠性來說是不可容忍的。
d. 重複的轉賬操作
a賬戶金額為¥200,b賬戶金額¥100
a呼叫api向b轉賬¥100,由於a的誤操作發出了第二次同樣的請求
a發出的兩次請求均成功
a賬戶金額為¥0,b賬戶金額¥300
兩次操作同時發出,並且都成功,介面沒有實現冪等的情況下,兩次轉賬操作都會成功,但是對於使用者a來說,實際上這是同一次的轉賬意願。
以上的場景還是在a與b賬戶均存在於同乙個資源(一般為資料庫)之上的操作,如果a與b賬戶處於兩個資源,場景還會更加的複雜。
由上述的場景可以看出,實現介面冪等性的兩個方向在於:
定義同一次操作
拒絕重複操作
實現利用資料庫實現上述兩個需求十分方便。
定義同一次操作
使用資料庫實現發號器,為每一次請求生成唯一編號
拒絕重複操作
通過資料庫事務以及唯一索引,以請求編號作為依據,保證同一時間內只有乙個請求進行操作,經過先查詢後操作的方式,已完成操作不執行更改邏輯,保證請求值執行一次。
以mysql為例,針對需要實現冪等的操作,可以建立如下的資料表:
create table `idempotent_op` (
`id` int(11) unsigned not null auto_increment,
`op_no` char(32) not null default '',
`status` int(11) not null,
primary key (`id`),
unique key `op_no` (`op_no`)
) engine=innodb default charset=utf8;
createtable`idempotent_op`(
`id`int(11)unsignednotnullauto_increment,
`op_no`char(32)notnulldefault'',
`status`int(11)notnull,
primarykey(`id`),
uniquekey`op_no`(`op_no`)
)engine=innodbdefaultcharset=utf8;
其中op_no列存在唯一索引。
針對上述轉賬的場景,設定a與b都處於同一資料庫中,可以用如下偽**表示上述的轉賬操作:
# 非事務讀,判斷是否當前請求已處理,減少事務數量
if select op_no_a in idempotent_op and (status of op_no_a) == 'finished' then
return 'transfer handled'
begin transaction
# 在事務讀中使用x鎖,保證只有乙個請求完成本次轉賬
if select op_no_a in idempotent_op for update then
if (status of op_no_a) == 'finished' then
rollback
return 'transfer handled'
else
if do_transfer(a, b, money) == success then
set status of op_no_a from 'created' to 'finished'
commit
else
rollback
return 'transfer failed'
else
# 資料庫唯一鍵保證同時到達的多個新請求只有乙個可以進行轉賬操作
result = insert (op_no=op_no_a, status='create') into idempotent_op
if result = fail then
rollback
return 'transfer insert record failed'
if do_transfer(a, b, money) == success then
set status of op_no_a from 'created' to 'finished'
commit
else
rollback
return 'transfer failed'
# 非事務讀,判斷是否當前請求已處理,減少事務數量
ifselectop_no_ainidempotent_opand(statusofop_no_a)=='finished'then
return'transfer handled'
begintransaction
# 在事務讀中使用x鎖,保證只有乙個請求完成本次轉賬
ifselectop_no_ainidempotent_opforupdatethen
if(statusofop_no_a)=='finished'then
rollback
return'transfer handled'
else
ifdo_transfer(a,b,money)==successthen
setstatusofop_no_afrom'created'to'finished'
commit
else
rollback
return'transfer failed'
else
# 資料庫唯一鍵保證同時到達的多個新請求只有乙個可以進行轉賬操作
result=insert(op_no=op_no_a,status='create')intoidempotent_op
ifresult=failthen
rollback
return'transfer insert record failed'
ifdo_transfer(a,b,money)==successthen
setstatusofop_no_afrom'created'to'finished'
commit
else
rollback
return'transfer failed'
以上針對於只有乙個業務方/使用者的場景,如果有多個業務方的情況下,只需要在冪等操作表中增加乙個**字段(如名為source),並對source欄位與op_no做聯合的唯一索引即可。
create table `idempotent_op` (
`id` int(11) unsigned not null auto_increment,
`source` int(11) not null default 0,
`op_no` char(32) not null default '',
`status` int(11) not null,
primary key (`id`),
unique key `op_no` (`source`, `op_no`)
) engine=innodb default charset=utf8;
createtable`idempotent_op`(
`id`int(11)unsignednotnullauto_increment,
`source`int(11)notnulldefault0,
`op_no`char(32)notnulldefault'',
`status`int(11)notnull,
primarykey(`id`),
uniquekey`op_no`(`source`,`op_no`)
)engine=innodbdefaultcharset=utf8;
事實上,在所有操作都帶有前置狀態的情況下(即所有改動都顯示的指明上乙個狀態),如果介面操作只有一步,而沒有多個步驟需要同時成功失敗的情況下,甚至不需要顯式的開啟事務。
以上。
資料庫新增冪等操作 基於資料庫實現冪等介面
tl dr 通過唯一編號確定同一請求,沒有唯一編號的自行生成。資料庫記錄操作狀態,資料庫事務保證資料一致性。概述通過http api進行通訊的系統,在支付或者只允許操作一次的相關場景中,對介面的冪等性有嚴格要求。介面的冪等性體現在 請求執行成功所得到的結果與次數無關 如果介面沒有實現冪等性,對於轉賬...
資料庫冪等性的實現方法
使用資料庫實現冪等性的方法有三種 通過悲觀鎖來實現冪等性 通過唯一索引來實現冪等性 通過樂觀鎖來實現冪等性 接下來我們分別來看這些實現方式的具體執行過程。悲觀鎖 使用悲觀鎖實現冪等性,一般是配合事務一起來實現,在沒有使用悲觀鎖時,我們通常的執行過程是這樣的,首先來判斷資料的狀態,執行 sql 如下 ...
資料庫新增冪等操作 使用資料庫唯一鍵實現事務冪等性
冪等性 概念在分布式系統中,冪等性是一致性方面的乙個重要概念。冪等 idempotent idempotence 是乙個數學與計算機學概念,常見於抽象代數中。在程式設計中乙個冪等操作的特點是其任意多次執行所產生的影響均與一次執行的影響相同。所謂 影響相同 不是要求返回值完全相同,而且是指後續多餘的呼...