java幂等性的控制(技术论坛上整理成文)
轉(zhuǎn)載自?https://blog.csdn.net/mine_song/article/details/70992385
本文是從技術(shù)論壇上大家一人一句沒(méi)有條理的講解,我整理一下發(fā)到CSDN上,希望對(duì)大家有用。
什么是冪等性
抄用一段數(shù)學(xué)上的定義:f(f(x)) =?f(x)。x被函數(shù)f作用一次和作用無(wú)限次的結(jié)果是一樣的。冪等性應(yīng)用在軟件系統(tǒng)中,我把它簡(jiǎn)單定義為:某個(gè)函數(shù)或者某個(gè)接口使用相同參數(shù)調(diào)用一次或者無(wú)限次,其造成的后果是一樣的,在實(shí)際應(yīng)用中一般針對(duì)于接口進(jìn)行冪等性設(shè)計(jì)。舉個(gè)栗子,在系統(tǒng)中,調(diào)用方A調(diào)用系統(tǒng)B的接口進(jìn)行用戶(hù)的扣費(fèi)操作時(shí),由于網(wǎng)絡(luò)不穩(wěn)定,A重試了N次該請(qǐng)求,那么不管B是否接收到多少次請(qǐng)求,都應(yīng)該保證只會(huì)扣除該用戶(hù)一次費(fèi)用。
加深對(duì)冪等性的了解
冪等性一般應(yīng)用于協(xié)議設(shè)計(jì),TCP協(xié)議支持冪等嗎?答案是肯定的,在網(wǎng)絡(luò)不穩(wěn)定時(shí),操作系統(tǒng)可以肆無(wú)忌憚的重發(fā)TCP報(bào)文片段。TCP協(xié)議能夠保證冪等的核心在于sequence number字段,一個(gè)序列號(hào)的在較長(zhǎng)的一段時(shí)間內(nèi)均不會(huì)出現(xiàn)重復(fù)。對(duì)于應(yīng)用層的協(xié)議設(shè)計(jì),原理和TCP是類(lèi)似的,我們需要一個(gè)不重復(fù)的序列號(hào)。再簡(jiǎn)單一點(diǎn)說(shuō),在一個(gè)業(yè)務(wù)流程的處理中,我們需要一個(gè)不重復(fù)的業(yè)務(wù)流水號(hào),以保證冪等性。
舉個(gè)實(shí)際應(yīng)用場(chǎng)景:用戶(hù)A在網(wǎng)頁(yè)上發(fā)起一筆游戲充值請(qǐng)求,瀏覽器引導(dǎo)用戶(hù)去銀行支付,支付成功后系統(tǒng)給用戶(hù)進(jìn)行充值。
協(xié)議設(shè)計(jì)上,我們通過(guò)全局唯一的充值訂單號(hào)貫穿整個(gè)業(yè)務(wù)流程,使該業(yè)務(wù)支持冪等。
我們先從一個(gè)簡(jiǎn)單的程序理解一下冪等性:
public class Main {
private int i = 0;
//這個(gè)方法不具有冪等性,每調(diào)用一次,它就會(huì)改變Main的狀態(tài)(即改變了i)
public void idempotent() {
i++;
}
//冪等性,無(wú)論這個(gè)方法調(diào)用多少次,它都不會(huì)改變Main類(lèi)的狀態(tài)。
public void simple() {
System.out.println(i);
}
}
看完這些,你似乎對(duì)冪等性有了更深的了解。那么冪等性問(wèn)題會(huì)出現(xiàn)在哪些場(chǎng)景呢?
電商,第三方支付,搶紅包等場(chǎng)景。
這些應(yīng)用場(chǎng)景,你似乎看到了他們的共同特征。對(duì),那就是高并發(fā)。
冪等控制的實(shí)現(xiàn)
HTTP的冪等性
冪等表示:請(qǐng)求服務(wù)器一次或是多次,返回的結(jié)果均是一樣的【select?】一般是GET請(qǐng)求
非冪等表示:請(qǐng)求服務(wù)器不同的次數(shù),返回的結(jié)果將是不一樣的[update???delete] 一般是POST請(qǐng)求
HTTP協(xié)議本身是一種面向資源的應(yīng)用層協(xié)議,但對(duì)HTTP協(xié)議的使用實(shí)際上存在著兩種不同的方式:一種是restful,它把HTTP當(dāng)成應(yīng)用層協(xié)議,另一種是SOA,它并沒(méi)有完全把HTTP當(dāng)成應(yīng)用層協(xié)議,而是把HTTP協(xié)議作為了傳輸層協(xié)議,然后在HTTP之上建立了自己的應(yīng)用層協(xié)議。
restful風(fēng)格,想了解的可以去看看webservice編程,這里不是本文的主題。
本文所討論的HTTP冪等性主要針對(duì)RESTful風(fēng)格的,不過(guò)正如上一節(jié)所看到的那樣,冪等性并不屬于特定的協(xié)議,它是分布式系統(tǒng)的一種特性;所以,不論是SOA還是RESTful的Web API設(shè)計(jì)都應(yīng)該考慮冪等性。
?
| 重要方法 | 安全 | 冪等 |
| GET | 是 | 是 |
| POST | 否 | 否 |
| PUT | 否 | 是 |
| DELETE | 否 | 是 |
數(shù)據(jù)庫(kù)冪等
數(shù)據(jù)庫(kù)上的冪等和事務(wù)是一體的。
1. 查詢(xún)操作?
查詢(xún)一次和查詢(xún)多次,在數(shù)據(jù)不變的情況下,查詢(xún)結(jié)果是一樣的。select是天然的冪等操作?
?2. 刪除操作?
刪除操作也是冪等的,刪除一次和多次刪除都是把數(shù)據(jù)刪除。(注意可能返回結(jié)果不一樣,刪除的數(shù)據(jù)不存在,返回0,刪除的數(shù)據(jù)多條,返回結(jié)果多個(gè))?
3.唯一索引,防止新增臟數(shù)據(jù)?
比如:支付寶的資金賬戶(hù),支付寶也有用戶(hù)賬戶(hù),每個(gè)用戶(hù)只能有一個(gè)資金賬戶(hù),怎么防止給用戶(hù)創(chuàng)建資金賬戶(hù)多個(gè),那么給資金賬戶(hù)表中的用戶(hù)ID加唯一索引,所以一個(gè)用戶(hù)新增成功一個(gè)資金賬戶(hù)記錄?
4.悲觀(guān)鎖?
獲取數(shù)據(jù)的時(shí)候加鎖獲取?
select * from table_xxx where id='xxx' for update;?
注意:id字段一定是主鍵或者唯一索引,不然是鎖表,會(huì)死人的?
悲觀(guān)鎖使用時(shí)一般伴隨事務(wù)一起使用,數(shù)據(jù)鎖定時(shí)間可能會(huì)很長(zhǎng),根據(jù)實(shí)際情況選用?
5.?樂(lè)觀(guān)鎖?
樂(lè)觀(guān)鎖只是在更新數(shù)據(jù)那一刻鎖表,其他時(shí)間不鎖表,所以相對(duì)于悲觀(guān)鎖,效率更高。
?
客戶(hù)端冪等控制機(jī)制-token
業(yè)務(wù)要求:?
頁(yè)面的數(shù)據(jù)只能被點(diǎn)擊提交一次?
發(fā)生原因:?
由于重復(fù)點(diǎn)擊或者網(wǎng)絡(luò)重發(fā),或者nginx重發(fā)等情況會(huì)導(dǎo)致數(shù)據(jù)被重復(fù)提交?
解決辦法:?
集群環(huán)境:采用token加redis(redis單線(xiàn)程的,處理需要排隊(duì))?
單JVM環(huán)境:采用token加redis或token加jvm內(nèi)存?
處理流程:?
1. 數(shù)據(jù)提交前要向服務(wù)的申請(qǐng)token,token放到redis或jvm內(nèi)存,token有效時(shí)間?
2. 提交后后臺(tái)校驗(yàn)token,同時(shí)刪除token,生成新的token返回?
token特點(diǎn):?
要申請(qǐng),一次有效性,可以限流?
?
后期整理電商案例,直接上圖來(lái)說(shuō)一下一個(gè)電商網(wǎng)站在冪等控制上的方法。(待續(xù)。。。)
總結(jié)
以上是生活随笔為你收集整理的java幂等性的控制(技术论坛上整理成文)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Java如何查看死锁?
- 下一篇: mysql时间与字符串相互转换