點擊上方藍色字體,選擇「標星公衆號」前端
優質文章,第一時間送達java
做者: 軟件編程指南git
來源:http://suo.im/66liCE程序員
本文前篇是對場景的分析,後篇會有解決方案,讀完本篇你將能夠僅僅使用兩個註解便可解決併發重複提交問題。github
能夠直接看方案四,直接讀推薦解決方案。web
場景分析
重複提交問題是一個老生常談的問題,項目中常常會遇到這種狀況,這種狀況在查詢類接口其實也沒有太大問題,可是若是是在設計修改數據的接口就有會嚴重問題,可是這種狀況並也不難處理,由於咱們的代碼最少會作一個冪等判斷,即會先有一個查詢動做,查詢不到纔會放行。可是難就難在假如說是併發加劇復提交這種場景就很難處理。這個時候就不得不去思考新的解決方案。spring
解決方案
數據庫
方案1、編程
經過數據庫惟一索引來解決,即在數據庫建立一張惟一表,在每次數據請求時候將惟一鍵做爲數據插入這張惟一表中,正常狀況是能夠插入成功的,當出現重複提交狀況就會異常提示。後端
缺點
數據庫性能問題,由於每次操做都設計到數據庫的一次插入動做,因此可能會有性能問題
數據只有一次處理機會,當第一次處理失敗,第二次在進來就當重複給攔截了
方案2、
token令牌,後端提供一個生成令牌的接口,前端在每次進行數據訪問時候,先拿去token令牌,後端經過對token令牌的生命週期管控,來解決重複提交問題
缺點: 先後端改造大,後端要單獨維護一個接口,前端每次請求也要多調一個接口
總結
但願經過查詢+修改方式來解決併發和重複提交問題都是不現實的,由於不能保證查詢和修改是一個原子性操做,因此只要併發就很容易突破這種方式的防重邏輯。那麼如何解決這個問題呢? 其實就是保證防重邏輯的原子性操做。一樣也是兩種方案。
方案3、
相似於經過數據庫惟一索引這種方式,不一樣的是將數據庫換成內存緩存即項目裏定義一個Cache集合緩存能夠用Guava的緩存框架,設置緩存時間和緩存數量來解決。不過也是有缺點的,缺點就是不知足分佈式要求,當請求打到其餘應用服務器就突破了這種狀況。因此不建議使用這種方案。若是是單機器能夠考慮。
方案4、
是對上一種方案的改進,經過Redis實現,每次請求都插入Redis數據庫中,並設置過時時間, 既能知足性能需求,同時也知足分佈式狀況。同時Redis由於是單線程的因此也能保證原子性。綜上所述這種方案應該是最好的。
知足原子性
知足分佈式環境應用
性能有保證
支持重試(經過設置過時時間)
僞代碼以下
終結解決方案
該方案是對上面方案四的一個實現,感興趣的同窗一個start一下,而後拉下來看看實現原理。
核心原理就是方案四中提的,經過攔截和自動配置無縫整合到SpringBoot項目中使用。
官網地址: https://tomato.springlearn.cn/
使用方式
如何判斷是否引用成功
當出現tomato Logo即說明啓用成功
感興趣的同窗能夠學習一下代碼,提出任何問題小編都會第一時間回覆。一塊兒探討學習。
接下來小編會圍繞Redis作更多的實戰分享目前定下來的兩個議題是:
1.基於Redis原子性操做實戰應用一之併發攔截 「Tomato」
2.基於Redis原子性操做實戰應用二之防洪限流「Easy-Sentinel」
這兩個議題其實實戰代碼都已經寫好了,只是尚未總結成文,感興趣的同窗能夠先到github上拉去實戰代碼。Tomato就是解決併發致使的重複提交,而Easy-Sentinel會更高級一點,利用Redis+Lua腳本實現原子性操做,從而來達到防洪限流的能力。
關注程序員閃充寶後臺回覆「666」和「111」免費領取46階段以及實戰java視頻資料
看完本文有收穫?請轉發分享給更多人
長按識別二維碼關注
![](http://static.javashuo.com/static/loading.gif)
你在看?
看完本文有收穫?請轉發分享給更多人
長按識別二維碼關注
你在看?
本文分享自微信公衆號 - 程序員閃充寶(cxyscb1024)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。