1. 程式人生 > >mybatis 樂觀鎖實現,解決併發問題。

mybatis 樂觀鎖實現,解決併發問題。

https://blog.csdn.net/zhouzhiwengang/article/details/54973509轉載

情景展示:

銀行兩操作員同時操作同一賬戶就是典型的例子。

比如A,B操作員同時讀取一餘額為1000元的賬戶,A操作員為該賬戶增加100元,B操作員同時為該賬戶扣除50元,A先提交,B後提交。最後實際賬戶餘額為1000年至1050年= 950元,但本該為1000 + 100-50 = 1050。這就是典型的併發問題。

樂觀鎖機制在一定程度上解決了這個問題。樂觀鎖,大多是基於資料版本(版本)記錄機制實現。資料增加一個版本標識,在基本資料庫表的版本解決方案中,一般是通過為資料庫表增加一個“version”欄位來實現。

讀取出資料時,將此版本號一同讀出,之後更新時,對此版本號加一。此時,將提交資料的版本資料與資料庫表對應記錄的當前版本資訊進行比對
,如果提交的資料版本號大於資料庫表當前版本號,則予以更新,否則認為是過期資料。


對於上面修改使用者帳戶資訊的例子而言,假設資料庫中帳戶資訊表中有一個版本 欄位,當前值為1;而當前帳戶餘額欄位(餘額)為1000元。假設操作員A先更新完,操作員B後更新。a
,操作員A此時將其出讀(版本= 1),並從其帳戶餘額中增加100(1000 + 100 = 1100)
。b,在操作員A操作的過程中,操作員B也可以讀入此使用者資訊(版本= 1),並從其帳戶餘額中扣除50 (1000-50 = 950)
。c,操作員A完成了修改工作,將資料版本號加一(版本= 2),連同帳戶增加後餘額(餘額= 1100),提交至資料庫更新,此時由於提交資料版本大於資料庫記錄當前版本,資料被更新,資料庫記錄的版本更新為2。

d,操作員乙完成了操作,也將版本號加一(版本= 2)試圖向資料庫提交資料(餘量= 950),但此時比對資料庫記錄版本時發現,操作員乙提交的資料版本號為2,資料庫記錄當前版本也為2,不滿足“提交版本必須大於記錄當前版本才能執行更新”的樂觀鎖策略,因此,操作員B的提交被駁回。

這樣,就避免了操作員乙用基於版本= 1的舊資料修改的結果覆蓋操作員甲的操作結果的可能。

示例程式碼:

佔建庫指令碼

[html]  檢視純文字
  1. 刪除表如果存在account_wallet;  
  2. / * ================================================ ============== * /  
  3. / *表:account_wallet * /  
  4. / * ================================================ ============== * /  
  5. 建立表account_wallet  
  6. (  
  7.    id int not null評論'使用者錢包主鍵',  
  8.    user_open_id varchar(64)評論'使用者中心的使用者唯一編號',  
  9.    user_amount decimal(10,5),  
  10.    create_time datetime,  
  11.    update_time datetime,  
  12.    pay_password varchar(64),  
  13.    is_open int comment'0:代表未開啟支付密碼,1:代表開發支付密碼',  
  14.    check_key varchar(64)comment'平臺進行使用者餘額更改時,首先效驗鍵值,否則無法進行使用者餘額更改操作',  
  15.    版本int評論'基於mysql樂觀鎖,解決併發訪問'  
  16.    主鍵(id)  
  17. );  


DAO層

[html]  檢視純文字
  1. AccountWallet selectByOpenId(String openId);  
  2. int updateAccountWallet(AccountWallet記錄);  

服務層

[html]  檢視純文字
  1. AccountWallet selectByOpenId(String openId);  
  2. int updateAccountWallet(AccountWallet記錄);  

serviceImpl層

[html]  檢視純文字
  1. public AccountWallet selectByOpenId(String openId){  
  2.     // TODO自動生成的方法存根  
  3.     return accountWalletMapper.selectByOpenId(openId);  
  4. }  
  5. public int updateAccountWallet(AccountWallet record){  
  6.     // TODO自動生成的方法存根  
  7.      返回accountWalletMapper.updateAccountWallet(record);  
  8. }  

sql.xml

[html]  檢視純文字
  1. <! - 通過使用者唯一編號,查詢使用者錢包相關的資訊 - >
  2.  < select id = “selectByOpenId” resultMap = “BaseResultMap” parameterType = “java.lang.String” >
  3.      選擇   
  4.    < include refid = “Base_Column_List” />
  5.    來自account_wallet  
  6.    其中  user_open_id  =#{openId,jdbcType = VARCHAR }  
  7.  </ select >
  8.  <! - 使用者錢包資料更改,通過樂觀鎖(版本機制)實現 - >
  9.  < update id = “updateAccountWallet” parameterType = “com.settlement.model.AccountWallet” >
  10.          <![CDATA [ 
  11.             update account_wallet set user_amount = #{userAmount,jdbcType=DECIMAL}, version = version + 1 where id =#{id,jdbcType=INTEGER} and version = #{version,jdbcType=INTEGER}  
  12.           ]]>
  13.  </update>


controller 層

  1. package com.settlement.controller;  
  2. import java.math.BigDecimal;  
  3. import javax.servlet.http.HttpServletRequest;  
  4. import org.springframework.beans.factory.annotation.Autowired;  
  5. import org.springframework.stereotype.Controller;  
  6. import org.springframework.web.bind.annotation.RequestMapping;  
  7. import org.springframework.web.bind.annotation.RequestMethod;  
  8. import org.springframework.web.bind.annotation.ResponseBody;  
  9. import com.settlement.commons.base.BaseController;  
  10. import com.settlement.model.AccountWallet;  
  11. import com.settlement.service.AccountWalletService;  
  12. import com.taobao.api.internal.util.StringUtils;  
  13. /**  
  14.  * 使用者錢包Controller  
  15.  *   
  16.  * @author zzg  
  17.  * @date 2017-02-10  
  18.  */  
  19. @Controller  
  20. @RequestMapping(value = "/wallet")  
  21. public class WalletController extends BaseController {  
  22.     @Autowired  
  23.     private AccountWalletService accountWalletService;  
  24.     /**  
  25.      * 針對業務系統高併發-----修改使用者錢包資料餘額,採用樂觀鎖  
  26.      *   
  27.      * @return  
  28.      */  
  29.     @RequestMapping(value = "/walleroptimisticlock.action"method = RequestMethod.POST)  
  30.     @ResponseBody  
  31.     public String walleroptimisticlock(HttpServletRequest request) {  
  32.         String result = "";  
  33.         try {  
  34.             String openId = request.getParameter("openId") == null ? null  
  35.                     : request.getParameter("openId").trim(); // 使用者唯一編號  
  36.             String openType = request.getParameter("openType") == null ? null  
  37.                     : request.getParameter("openType").trim(); // 1:代表增加,2:代表減少  
  38.             String amount = request.getParameter("amount") == null ? null  
  39.                     : request.getParameter("amount").trim(); // 金額  
  40.             if (StringUtils.isEmpty(openId)) {  
  41.                 return "openId is null";  
  42.             }  
  43.             if (StringUtils.isEmpty(openType)) {  
  44.                 return "openType is null";  
  45.             }  
  46.             if (StringUtils.isEmpty(amount)) {  
  47. 相關推薦

    mybatis 樂觀實現解決併發問題

    https://blog.csdn.net/zhouzhiwengang/article/details/54973509轉載情景展示:銀行兩操作員同時操作同一賬戶就是典型的例子。比如A,B操作員同時讀取一餘額為1000元的賬戶,A操作員為該賬戶增加100元,B操作員同時為該

    樂觀 -業務判斷 解決併發問題

        在解決高併發問題時,如果是分散式系統顯然我們只能夠使用資料庫端加鎖機制來解決這個問題,但是這種同步機制或者資料庫物理鎖機制會犧牲一部分的效能,所以常常以另外一種方式來解決這個問題 就是樂觀鎖模式   銀行兩操作員同時操作同一賬戶就是典型的樂觀鎖模式。  &nb

    JPA事務併發樂觀實現隔離機制)

    事務(4個特性ACID) 原子性(atomic),事務必須是原子工作單元;對於其資料修改,要麼全都執行,要麼全都不執行 一致性(consistent),事務在完成時,必須使所有的資料都保持一致狀態。 隔離性(insulation),由事務併發所作的修改必須與任何其它併發事務所作的修改

    Hibernate併發控制樂觀實現-Version

    通過在表中及POJO中增加一個version欄位來表示記錄的版本,來達到多使用者同時更改一條資料的衝突 資料庫指令碼: createtable studentVersion (id varchar(32),name varchar(32),ver int); POJO package Versio

    若還 不懂 java synchronized 同步物件wait,notify問題看完這兩段程式碼解決問題

    <原文地址:http://blog.csdn.net/cnmm22/article/details/44273843> 看程式碼很累,特別看別人滴程式碼,又特別針對新人,但請你忍耐一下,看完這兩個單獨案例。 這兩個個程式碼的功能一樣,都是間斷列印1、2、1、

    中國有句俗語叫“三天打魚兩天晒網”某人從2010年1月1日起開始“三天打魚兩天晒網”問這個人在以後的某一天中是“打魚”還是“晒網”用C或C++語言/java/python實現程式解決問題

    提高要求:1.輸入資料的正確性驗證。           2.使用檔案進行資料測試。如將日期 20100101   20111214  等資料儲存在in.txt檔案中,程式讀入in.dat檔案進行判定,並將結果輸出至out.txt檔案。 import java.io.Bu

    的種類阻塞產生與解決辦法

    TM鎖的種類:   TM鎖幾種模式的互斥關係: 阻塞 定義: 當一個會話保持另一個會話正在請求的資源上的鎖定時,就會發生阻塞。被阻塞的會話將一直掛起,直到持有鎖的會話放棄鎖定的資源為止。4個常見的dml語句會產生阻塞 INSERT UPDATE DELET

    Elasticsearch系列---併發控制及樂觀實現原理

    概要 本篇主要介紹一下Elasticsearch的併發控制和樂觀鎖的實現原理,列舉常見的電商場景,關係型資料庫的併發控制、ES的併發控制實踐。 併發場景 不論是關係型資料庫的應用,還是使用Elasticsearch做搜尋加速的場景,只要有資料更新,併發控制是永恆的話題。 當我們使用ES更新document的時

    水晶報表 Crystal Report 調用存儲過程時出錯 找不到表 解決方法

    top app net amp lean local database sep asp.net 用 CrystalReportViewer1 控件在asp.net的網頁上顯示報表,假設做報表時調用數據表數據的方式調用是能夠成功的。但報表是用存儲過程獲

    mysql樂觀實現

    color new lan 什麽 clas 事務處理 帶來 解決 提交 一、為什麽需要鎖(並發控制)? 在多用戶環境中,在同一時間可能會有多個用戶更新相同的記錄,這會產生沖突。這就是著名的並發性問題。 典型的沖突有: 1.丟失更新:一

    nessus無法訪問https://localhost:8834/#/解決方法

    方法 啟動文件 服務 技術 ges net 權限 分享 無法 之前沒弄明白為啥經常訪問不了https://localhost:8834/#/,後面才發現是服務關閉了。 首先netstat -an 查看8834是否開啟, 直接運行一下nessus目錄下的nessusd.exe

    最長公共子串和子序列的Python實現帶圖示

    code mage 數字 實現 max 記錄 子串和 abc 使用 使用矩陣來記錄兩個子串之間各個字符之間的對應關系。 最長子串:矩陣中數字最大的就是最長子串的長度。若對應位置字符相同,則c[i][j] = c[i-1][j-1] + 1 1 def longSu

    mybatis 樂觀和邏輯刪除

    全局 conf lan 查詢 con upd print erl location 本篇介紹easymybatis如配置樂觀鎖和邏輯刪除。 樂觀鎖 easymybatis提供的樂觀鎖使用方式跟JPA一樣,使用@Version註解來實現。即:數據庫增加一個int或long類型

    JAVA樂觀實現-CAS

    sub 缺點 c語言 get get() fin mage 個數 接口實現 是什麽 全稱compare and swap,一個CPU原子指令,在硬件層面實現的機制,體現了樂觀鎖的思想。 JVM用C語言封裝了匯編調用。Java的基礎庫中有很多類就是基於JNI調用C接口實現了

    輸入兩個整數求他們相除的餘數用帶參的巨集來實現程式設計序

    import java.util.Scanner; public class Main {     public static void main(String[] args) {         Scanne

    phpstudy 提示安裝VC9 VC14等MySQL啟動失敗紅色小點點解決辦法PHP VC版本下載集合

    phpStudy啟動失敗時的解決方法 提示缺vc9執行庫 php5.3、5.4和apache都是用vc9編譯,電腦必須安裝vc9執行庫才能執行。 php5.5、5.6是vc11編譯,如用php5.5、5.6必須安裝vc11執行庫。 php7.0、7.1是vc14編譯,如用php7.0

    dede織夢繫統後臺的文章或自定義模型中的資料庫內容到匯出excel檔案解決亂碼

    dede織夢繫統後臺的文章或自定義模型中的資料庫內容到匯出excel檔案,解決亂碼。好品牌小編下面分享的開發過程。   1、在後臺目錄建立一個php檔案toexcel.php,在最上面加入程式碼: require_once(dirname(__FILE__).'/confi

    mysql 樂觀實現

    mysql 樂觀鎖實現 一、為什麼需要鎖(併發控制)?       在多使用者環境中,在同一時間可能會有多個使用者更新相同的記錄,這會產生衝突。這就是著名的併發性問題。       典型的衝突有:      

    springboot+websocket的簡單實現解決websocket failed: Error during WebSocket handshake: Unexpected response

    編輯器:idea。tomcat是springboot內建的tomcat,一開始出現 websocket failed: Error during WebSocket handshake: Unexpected response 這個問題的原因是,我一開始在專案中沒有在注入ServerEndp

    accept()函式用來告訴Qt事件處理函式“接收”了這個事件不要再傳遞;ignore()函式則告訴Qt事件處理函式“忽略”了這個事件需要繼續傳遞(看一下QWidget::mousePressEvent的實現,最為典型如果希望忽略事件只要呼叫父類的響應函式即可)

    QEvent的accept()和ignore()一般不會用到,因為不如直接呼叫QWidget類的事件處理函式直接,而且作用是一樣的,見下面的例子。 推薦直接呼叫QWidget的事件處理函式。而不是呼叫accept()和ignore()。   只有一種情況下,必須使用呼叫accept()和ign