MyBatisPlus樂觀鎖和悲觀鎖的實現(xiàn)示例
1.場景
一件商品,成本價是80元,售價是100元。老板先是通知小李,說你去把商品價格增加50元。小 李正在玩游戲,耽擱了一個小時。正好一個小時后,老板覺得商品價格增加到150元,價格太高,可能會影響銷量。又通知小王,你把商品價格降低30元。
此時,小李和小王同時操作商品后臺系統(tǒng)。小李操作的時候,系統(tǒng)先取出商品價格100元;小王 也在操作,取出的商品價格也是100元。小李將價格加了50元,并將100+50=150元存入了數(shù)據(jù) 庫;小王將商品減了30元,并將100-30=70元存入了數(shù)據(jù)庫。是的,如果沒有鎖,小李的操作就 完全被小王的覆蓋了。
現(xiàn)在商品價格是70元,比成本價低10元。幾分鐘后,這個商品很快出售了1千多件商品,老板虧1 萬多。
2.樂觀鎖和悲觀鎖
上面的故事,如果是樂觀鎖,小王保存價格前,會檢查下價格是否被人修改過了。如果被修改過 了,則重新取出的被修改后的價格, 150元,這樣他會將120元存入數(shù)據(jù)庫。
如果是悲觀鎖,小李取出數(shù)據(jù)后,小王只能等小李操作完之后,才能對價格進行操作,也會保證 最終的價格是120元。
3.樂觀鎖實現(xiàn)
添加插件:
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 添加分頁插件
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
// 添加樂觀鎖插件
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}創(chuàng)建表:
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)
);
添加數(shù)據(jù):
INSERT INTO t_product (id, NAME, price) VALUES (1, '外星人筆記本 ', 100);
如圖:

編寫實體類:
package com.qcby.entity;
import com.baomidou.mybatisplus.annotation.Version;
import lombok.Data;
@Data
public class Product {
private Long id;
private String name;
private Integer price;
@Version
private Integer version;
}mapper:
package com.qcby.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.qcby.entity.Product;
import org.springframework.stereotype.Repository;
@Repository
public interface ProductMapper extends BaseMapper<Product> {
}
測試:
package com.qcby;
import com.qcby.entity.Product;
import com.qcby.mapper.ProductMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class MybatisTestOptimisticLock {
@Autowired
private ProductMapper productMapper;
@Test
public void testOptimisticLock() {
// 小李查詢商品信息
Product productLi = productMapper.selectById(1L);
System.out.println("小李查詢價格: " + productLi.getPrice() + ", 版本: " + productLi.getVersion());
// 小王查詢商品信息
Product productWang = productMapper.selectById(1L);
System.out.println("小王查詢價格: " + productWang.getPrice() + ", 版本: " + productWang.getVersion());
// 小李修改價格 +50
productLi.setPrice(productLi.getPrice() + 50);
int resultLi = productMapper.updateById(productLi);
System.out.println("小李修改結(jié)果: " + resultLi);
if (resultLi > 0) {
Product afterLi = productMapper.selectById(1L);
System.out.println("小李修改后價格: " + afterLi.getPrice() + ", 版本: " + afterLi.getVersion());
}
// 小王修改價格 -30
productWang.setPrice(productWang.getPrice() - 30);
int resultWang = productMapper.updateById(productWang);
System.out.println("小王修改結(jié)果: " + resultWang);
if (resultWang == 0) {
// 小王修改失敗,需要重新嘗試
System.out.println("小王修改失敗,版本已變更,需要重新操作");
Product newProductWang = productMapper.selectById(1L);
newProductWang.setPrice(newProductWang.getPrice() - 30);
resultWang = productMapper.updateById(newProductWang);
System.out.println("小王重試結(jié)果: " + resultWang);
}
// 最終價格
Product finalProduct = productMapper.selectById(1L);
System.out.println("最終價格: " + finalProduct.getPrice() + ", 版本: " + finalProduct.getVersion());
}
}


實際流程:
1. 小李查詢: SELECT id,name,price,version FROM t_product WHERE id=1
結(jié)果: price=100, version=02. 小王查詢: SELECT id,name,price,version FROM t_product WHERE id=1
結(jié)果: price=100, version=03. 小李更新: UPDATE t_product SET name=?, price=150, version=1
WHERE id=1 AND version=0
成功: version變?yōu)?4. 小王更新: UPDATE t_product SET name=?, price=70, version=1
WHERE id=1 AND version=0
失敗: version條件不匹配5. 小王重試: 重新查詢 price=150, version=1
更新: SET price=120, version=2 WHERE id=1 AND version=1
成功6. 最終價格: 120元 (正確的價格)
4.悲觀鎖
悲觀鎖總是假設(shè)最壞的情況,認(rèn)為共享資源每次被訪問的時候就會出現(xiàn)問題(比如共享數(shù)據(jù)被修改),所以每次在獲取資源操作的時候都會上鎖,這樣其他線程想拿到這個資源就會阻塞直到鎖被上一個持有者釋放。也就是說,共享資源每次只給一個線程使用,其它線程阻塞,用完后再把資源轉(zhuǎn)讓給其它線程。

到此這篇關(guān)于MyBatisPlus樂觀鎖和悲觀鎖的實現(xiàn)示例的文章就介紹到這了,更多相關(guān)MyBatisPlus樂觀鎖和悲觀鎖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用SpringSecurity設(shè)置角色和權(quán)限的注意點
這篇文章主要介紹了使用SpringSecurity設(shè)置角色和權(quán)限的注意點,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03
使用springboot對外部靜態(tài)資源文件的處理操作
這篇文章主要介紹了使用springboot對外部靜態(tài)資源文件的處理操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08
詳解SpringBoot如何實現(xiàn)統(tǒng)一后端返回格式
在前后端分離的項目中后端返回的格式一定要友好,不然會對前端的開發(fā)人員帶來很多的工作量。那么SpringBoot如何做到統(tǒng)一的后端返回格式呢?本文將為大家詳細講講2022-04-04
Java高級之HashMap中的entrySet()方法使用
這篇文章主要介紹了Java高級之HashMap中的entrySet()方法使用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-03-03
解決Java?properties文件里面如何寫"\"的問題
由于properties使用“\”相當(dāng)于是java的轉(zhuǎn)義符,如果想要寫出\的效果,只需修改相應(yīng)的寫法即可,對java?properties文件里的"\"寫法感興趣的朋友一起看看吧2022-04-04

