日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

MyBatisPlus的乐观锁和悲观锁

發布時間:2023/12/20 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MyBatisPlus的乐观锁和悲观锁 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

MyBatisPlus的樂觀鎖和悲觀鎖

  • 1.樂觀鎖
    • 1.1 場景
  • 2.0 樂觀鎖與悲觀鎖
  • 3.0 模擬修改沖突
    • Demo
  • 4.0 通過樂觀鎖觀念解決問題

文章順序及整體目錄可查看(點我即可)

1.樂觀鎖

**作用:**當要更新一條記錄的時候,希望這條記錄沒有被別人更新

樂觀鎖的實現方式:

取出記錄時,獲取當前 version 更新時,帶上這個 version 執行更新時, set version = newVersion
where version = oldVersion 如果 version 不對,就更新失敗

1.1 場景

  • 一件商品,成本價是80元,售價是100元。老板先是通知小李,說你去把商品價格增加50元。小李正在玩游戲,耽擱了一個小時。正好一個小時后,老板覺得商品價格增加到150元,價格太高,可能會影響銷量。又通知小王,你把商品價格降低30元。

  • 此時,小李和小王同時操作商品后臺系統。小李操作的時候,系統先取出商品價格100元;小王也在操作,取出的商品價格也是100元。小李將價格加了50元,并將100+50=150元存入了數據庫;小王將商品減了30元,并將100-30=70元存入了數據庫。是的,如果沒有鎖,小李的操作就完全被小王的覆蓋了。

  • 現在商品價格是70元,比成本價低10元。幾分鐘后,這個商品很快出售了1千多件商品,老板虧1萬多。

理解:同時操作的數據會使數據覆蓋;

2.0 樂觀鎖與悲觀鎖

  • 上面的故事,如果是樂觀鎖,小王保存價格前,會檢查下價格是否被人修改過了。如果被修改過了,則重新取出的被修改后的價格,150元,這樣他會將120元存入數據庫。

  • 如果是悲觀鎖,小李取出數據后,小王只能等小李操作完之后(有一個操作的時候另一人操作會被阻塞也就是無法操作),才能對價格進行操作,也會保證最終的價格是120元。(也就是說你先弄 你弄完之后我才能弄;也就不會導致上面的問題)

3.0 模擬修改沖突

數據庫中增加商品表

CREATE TABLE t_product ( id BIGINT(20) NOT NULL COMMENT '主鍵ID', NAME VARCHAR(30) NULL DEFAULT NULL COMMENT '商品名稱', price INT(11) DEFAULT 0 COMMENT '價格', VERSION INT(11) DEFAULT 0 COMMENT '樂觀鎖版本號', PRIMARY KEY (id) );

添加一條數據

INSERT INTO t_product (id, NAME, price) VALUES (1, '外星人筆記本', 100);

添加一個實體類Product

@Data public class Product {private Long id;private String name;private Integer price;private Integer version; }

添加一個Mapper接口ProductMapper

package com.example.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.example.pojo.Product;public interface ProductMapper extends BaseMapper<Product> {}

Demo

按照上面的說明我們來模擬場景進行測試;

@Testpublic void testProduct01(){//1.小李獲取商品價格Product productLi = productMapper.selectById(1);System.out.println("小李獲取的商品價格為:" + productLi.getPrice());//2.小王獲取商品價格Product productWang = productMapper.selectById(1);System.out.println("小王獲取的商品價格為:" + productWang.getPrice());//3.小李修改商品價格+50productLi.setPrice(productLi.getPrice()+50);productMapper.updateById(productLi);//4.小王修改商品價格-30productWang.setPrice(productWang.getPrice()-30);productMapper.updateById(productWang);//5.老板查詢商品價格Product productBoss = productMapper.selectById(1);System.out.println("老板獲取的商品價格為:" + productBoss.getPrice());}

我們一起來看下執行的過程:



執行結果展示

JDBC Connection [HikariProxyConnection@421632334 wrapping com.mysql.cj.jdbc.ConnectionImpl@43c87306] will not be managed by Spring ==> Preparing: SELECT id,name,price,version FROM t_product WHERE id=? ==> Parameters: 1(Integer) <== Columns: id, name, price, version <== Row: 1, 外星人筆記本, 100, 0 <== Total: 1 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4487c0c2] 小李獲取的商品價格為:100 Creating a new SqlSession SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3b705be7] was not registered for synchronization because synchronization is not active JDBC Connection [HikariProxyConnection@981012032 wrapping com.mysql.cj.jdbc.ConnectionImpl@43c87306] will not be managed by Spring ==> Preparing: SELECT id,name,price,version FROM t_product WHERE id=? ==> Parameters: 1(Integer) <== Columns: id, name, price, version <== Row: 1, 外星人筆記本, 100, 0 <== Total: 1 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3b705be7] 小王獲取的商品價格為:100 Creating a new SqlSession SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@63d5874f] was not registered for synchronization because synchronization is not active JDBC Connection [HikariProxyConnection@796851467 wrapping com.mysql.cj.jdbc.ConnectionImpl@43c87306] will not be managed by Spring ==> Preparing: UPDATE t_product SET name=?, price=?, version=? WHERE id=? ==> Parameters: 外星人筆記本(String), 150(Integer), 0(Integer), 1(Long) <== Updates: 1 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@63d5874f] Creating a new SqlSession SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@8cc8cdb] was not registered for synchronization because synchronization is not active JDBC Connection [HikariProxyConnection@505635448 wrapping com.mysql.cj.jdbc.ConnectionImpl@43c87306] will not be managed by Spring ==> Preparing: UPDATE t_product SET name=?, price=?, version=? WHERE id=? ==> Parameters: 外星人筆記本(String), 70(Integer), 0(Integer), 1(Long) <== Updates: 1 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@8cc8cdb] Creating a new SqlSession SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1fc713c9] was not registered for synchronization because synchronization is not active JDBC Connection [HikariProxyConnection@1929506494 wrapping com.mysql.cj.jdbc.ConnectionImpl@43c87306] will not be managed by Spring ==> Preparing: SELECT id,name,price,version FROM t_product WHERE id=? ==> Parameters: 1(Integer) <== Columns: id, name, price, version <== Row: 1, 外星人筆記本, 70, 0 <== Total: 1 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1fc713c9] 老板獲取的商品價格為:70

4.0 通過樂觀鎖觀念解決問題

實體類version字段添加注解@Version

private Long id;private String name;private Integer price;@Version //表示樂觀鎖版本號字段private Integer version;

package com.example.config;import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import org.mybatis.spring.annotation.MapperScan; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;@Configuration //地址指向mappe層 持久層也就是Dao接口 @MapperScan("com.example.mapper") public class MyBatisPlusConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {//調用的mybatis的分頁攔截器MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();//我們在此選擇數據庫的類型,也有其他的參數 我這邊選擇的mysqlinterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));//添加樂觀鎖插件interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());return interceptor;}}


添加之后我再次進行測試查看測試的結果(test代碼不變)

@Autowiredprivate ProductMapper productMapper;@Testpublic void testProduct01(){//1.小李獲取商品價格Product productLi = productMapper.selectById(1);System.out.println("小李獲取的商品價格為:" + productLi.getPrice());//2.小王獲取商品價格Product productWang = productMapper.selectById(1);System.out.println("小王獲取的商品價格為:" + productWang.getPrice());//3.小李修改商品價格+50productLi.setPrice(productLi.getPrice()+50);productMapper.updateById(productLi);//4.小王修改商品價格-30productWang.setPrice(productWang.getPrice()-30);productMapper.updateById(productWang);//5.老板查詢商品價格Product productBoss = productMapper.selectById(1);System.out.println("老板獲取的商品價格為:" + productBoss.getPrice());}

查看運行結果:


第一次修改之后就會導致version為2

小李查詢商品信息:? SELECT id,name,price,version FROM t_product WHERE id=?小王查詢商品信息:? SELECT id,name,price,version FROM t_product WHERE id=?小李修改商品價格,自動將version+1? UPDATE t_product SET name=?, price=?, version=? WHERE id=? AND version=?? Parameters: 外星人筆記本(String), 150(Integer), 1(Integer), 1(Long), 0(Integer)小王修改商品價格,此時version已更新,條件不成立,修改失敗? UPDATE t_product SET name=?, price=?, version=? WHERE id=? AND version=?? Parameters: 外星人筆記本(String), 70(Integer), 1(Integer), 1(Long), 0(Integer)最終,小王修改失敗,查詢價格:150? SELECT id,name,price,version FROM t_product WHERE id=?

修改測試的代碼:

@Testpublic void testProduct01(){//1.小李獲取商品價格Product productLi = productMapper.selectById(1);System.out.println("小李獲取的商品價格為:" + productLi.getPrice());//2.小王獲取商品價格Product productWang = productMapper.selectById(1);System.out.println("小王獲取的商品價格為:" + productWang.getPrice());//3.小李修改商品價格+50productLi.setPrice(productLi.getPrice()+50);productMapper.updateById(productLi);int result = productMapper.updateById(productWang);if(result == 0){//操作失敗,重試Product productNew = productMapper.selectById(1);productNew.setPrice(productNew.getPrice()-30);productMapper.updateById(productNew);}//4.小王修改商品價格-30productWang.setPrice(productWang.getPrice()-30);productMapper.updateById(productWang);//5.老板查詢商品價格Product productBoss = productMapper.selectById(1);System.out.println("老板獲取的商品價格為:" + productBoss.getPrice());}

我們來看看執行;



結果正常;解決了樂觀鎖的問題;

總結

以上是生活随笔為你收集整理的MyBatisPlus的乐观锁和悲观锁的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。