mybatisplus 结果_springboot整合mybatisPlus 乐观锁的实现
1:樂觀鎖
1.1:樂觀鎖簡介
樂觀鎖:總是假設最好的情況,在讀取數據的使用不會發生并發問題,但在更新的時候比較原數據是否被其他線程發生了改變。主要通過通過版本號機制或CAS算法實現,適用于讀多寫少的應用場景。
版本號機制:在數據庫表中加一個版本號version字段,表示數據被修改的次數,在修改數據前先讀取該表中的版本號字段,在修改的使用對比是否是自己讀取出來的版本號如果是則進行更新操作并版本號(version)加1如果不是則重新執行進行更新操作直到更新成功為止。
CAS:compare and swap 顧名思義就是比較與替換。CAS 操作包含三個操作數 —— 內存位置(V)、預期原值(A)和新值(B)。
內存位置的值是否與預期原值一樣如果一樣則用新值更新,如果不則重試。CAS算法實現會導致ABA問題的產生。
ABA問題:A線程某一時刻獲取內存位置的值為10,與其原值也為10,在這個過程中假設B線程對內存位置的值進行了修改,修改我為12,下一毫米又對內存中的值進行了修改,修改為10。這是A線程把值修改為13修改成功。這就是ABA問題。通俗易懂的來講就是:你大爺是你大爺,你大媽已經不是你大媽了。樂觀鎖通常使用版本號機制來避免ABA問題。
1.2:樂觀鎖的例子
未使用樂觀鎖(實現存錢取錢)
| 查詢余額(100¥) | 查詢余額(100¥) |
| 存入10¥(100¥+10¥) | 喝咖啡中 |
| 喝咖啡中 | 取出10¥(100¥-10¥) |
| 查詢余額 (90¥) | 喝咖啡中 |
| 查詢余額 (90¥) | 查詢余額 (90¥) |
以使用樂觀鎖(實現存錢取錢)
| 查詢余額(100¥)version=1 | 查詢余額(100¥)version=1 |
| 存入10¥(100¥+10¥)把查詢余額中的version進行對比匹配version+1充值成功 | 喝咖啡中 |
| 喝咖啡中 | 取出10¥(100¥-10¥)把查詢余額中的version進行對比,結果不匹配 ,取出不成功,重新進行取錢操作,查詢余額(110¥)version=2,把查詢余額中的version進行對比匹配version+1取出成功 (110¥-10¥) |
| 查詢余額 (100¥) | 喝咖啡中 |
| 查詢余額 (100¥) | 查詢余額 (100¥) |
2:springboot整合mybatisPlus 樂觀鎖插件
本章會設計到 springboot整合mybatisPlus整合使用,springboot整合swagger2整合使用,需要的可以看我其他的博文
2.1 插件配置
package cloud.xingzhe.springbootmybatisplus;import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
@MapperScan("cloud.xingzhe.springbootmybatisplus.mapper")
public class SpringbootMybatisPlusApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootMybatisPlusApplication.class, args);
}
/**
*樂觀鎖插件
*/
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
2.2 注解實體字段 @Version 必須要!
package cloud.xingzhe.springbootmybatisplus.model;import java.io.Serializable;
import com.baomidou.mybatisplus.annotation.Version;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import javax.validation.Valid;
/**
* @author 行者
* @since 2020-05-08
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@ApiModel(value="Bank對象", description="")
public class Bank implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
@ApiModelProperty(value = "余額")
private Integer amount;
@ApiModelProperty(value = "版本號")
@Version
private Integer version;
@ApiModelProperty(value = "用戶id")
private Integer userId;
}
特別說明:
支持的數據類型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
整數類型下 newVersion = oldVersion + 1
newVersion 會回寫到 entity 中
僅支持 updateById(id) 與 update(entity, wrapper) 方法
在 update(entity, wrapper) 方法下, wrapper 不能復用!!!
3:代碼演示
3.1:數據庫表
CREATE TABLE?bank?(id?int(11) NOT NULL,amount?int(10) NULL DEFAULT NULL COMMENT ‘余額’,version?int(5) NULL DEFAULT NULL COMMENT ‘版本號’,user_id?int(11) NULL DEFAULT NULL COMMENT ‘用戶id’,
PRIMARY KEY (id) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
INSERT INTO?bank?VALUES (1, 100, 0, 2);
3.2:測試并發接口
package cloud.xingzhe.springbootmybatisplus.controller;import cloud.xingzhe.springbootmybatisplus.model.Bank;
import cloud.xingzhe.springbootmybatisplus.service.IBankService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
/**
*
* 前端控制器
*
* @author 行者
* @since 2020-05-08
*/
@Api(tags = "銀行管理")
@RestController
@RequestMapping("/sys/bank")
public class BankController {
@Autowired
private IBankService bankService;
@ApiOperation(value="存取測試樂觀鎖")
@RequestMapping(value = "/access",method = RequestMethod.GET)
@ResponseBody
public String access(String userId,Integer money) throws InterruptedException {
QueryWrapper<Bank> queryWrapper=new QueryWrapper<>();
queryWrapper.eq("user_id", userId);
Bank bank = bankService.getOne(queryWrapper);
Integer amount= bank.getAmount();
bank.setAmount(amount+money);
Thread.sleep(5000);
boolean b = bankService.updateById(bank);
if (b){
return "更新成功";
}
return "更新失敗,余額已被其他操作人員修改,請重試";
}
}
3.2:接口訪問截圖
注意:開兩個swagger2 頁面進行測試 ,測試的money的參數最好不一樣 (有些瀏覽器接口和參數完全一樣會等待接口數據放回才再次請求)
數據庫中的version字段會每次都會加一 可以觀察看看
5:相關連接:
源碼地址:https://github.com/xingzhewenzi/springboot-examples.git
用到的博文地址:
springboot整合mybatis-plus(1) mybatis魂斗羅兄弟p2 實現單表curd零sql
springboot整合mybatisPlus代碼生成器 快速生成controller service mapper
springboog整合swagger2 實現便捷高效的接口文檔
總結
以上是生活随笔為你收集整理的mybatisplus 结果_springboot整合mybatisPlus 乐观锁的实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: git 移动分支指针_git 分支( b
- 下一篇: 前馈pid系数_SPMSM控制——基于模