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:乐观锁的例子
未使用乐观锁(实现存钱取钱)
A操作人员 | B操作人员 |
---|---|
查询余额(100¥) | 查询余额(100¥) |
存入10¥(100¥+10¥) | 喝咖啡中 |
喝咖啡中 | 取出10¥(100¥-10¥) |
查询余额 (90¥) | 喝咖啡中 |
查询余额 (90¥) | 查询余额 (90¥) |
以使用乐观锁(实现存钱取钱)
A操作人员 | B操作人员 |
---|---|
查询余额(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);}/** *乐观锁插件 */@Beanpublic 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 = "版本号")@Versionprivate 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 乐观锁的实现相关推荐
- springboot pom文件添加mysql组件_SpringBoot整合mybatis-plus+druid组件,实现增删改查
前言 本篇文章主要介绍的是SpringBoot整合mybatis-plus,实现增删改查. GitHub源码链接位于文章底部. 建库建表 创建springboot数据库,创建t_user表,字段id主 ...
- mybatis if test 用法_SpringBoot整合Mybatis-Plus 实战之动态SQL,Mybatis拿得出手的功能之一...
MyBatis的动态SQL是最令人喜欢的功能 在了解 动态SQL之前,你首先得知道一个表达式 OGNL,这个是基础! 面试常问问题 : Mybatis 中$与#的区别? 是将传入的值当做字符串的形式, ...
- 【Mybatis-Plus】(四)分页、乐观锁插件 通用枚举 多数据源
写在前面
- springboot 整合redis | 乐观锁实现商品秒杀
CSDN话题挑战赛第2期 参赛话题:Java技术分享 文章目录 优惠卷秒杀 ⚡1.1 - 全局唯一 ID
- mybatis-plus使用乐观锁插件
参考博文 https://baijiahao.baidu.com/s?id=1659469738216922362&wfr=spider&for=pc 1 没有锁的风险 开发不设锁,就 ...
- 尚医通——后台搭建——MybatisPlus自动填充和乐观锁
目录标题 自动填充和乐观锁 1.更新操作 2.自动填充 1.1数据库修改 1.2实体类修改 1.3实现元对象处理器接口 3.乐观锁 3.1场景 4.乐观锁实现流程 4.1修改实体类 4.2创建配置文件 ...
- springboot整合MybatisPlus【三】逻辑删除、乐观锁
1.在 application.properties 中添加一个配置(如果删除为1,不删除为0,这一步就可以不用配置) #该配置表示删除时为1,不删除时为0 #也可以不配置这两行,因为默认就是删除为 ...
- Springboot整合MyBatis-plus:乐观锁和悲观锁
乐观锁和悲观锁 乐观锁:十分乐观,总是认为不会出现问题,无论干什么都不去上锁,如果出现了问题,再次更新值测试. 悲观锁:十分悲观,总是认为会出现问题,无论干什么都会上锁,再去操作. 一.乐观锁插件 适 ...
- MyBatis-Plus 乐观锁 防止超卖、逻辑删除、自动填充、Id自增
MyBatis-Plus 乐观锁 防止超卖.逻辑删除.自动填充 Day3 前面的简单的讲了一下mybatis-plus的使用 当然有很多不足 我写博客就是想促进大家一起学习 也想让这些内容更简单一些. ...
最新文章
- vc6中进行多行注释和反注释的方法
- concurrenthashmap_ConcurrentHashMap实现原理及源码分析
- 音频监控叫好又叫座,核心部件拾音器怎么装?
- 将Calendar对象转换为日期时间字符串
- python3 TypeError: 'str' does not support the buffer interface in python
- 4月数据库流行度排行出炉:MySQL 成事实王者
- android 自动化 录制,android 自动化录制回放测试工具
- Spring框架学习-Spring和IOC概述
- 战地1服务器性能红色,FPS《战地1》PC性能测试:对显卡要求不高但很吃CPU
- 页面适配之pt、px、em、rem用法和特点
- 获取浏览器的地理位置信息
- oppo手机工程模式清除数据需要密码_普通人也可以做码农?黑客教你如何在手机上开发运用代码...
- springboot-shiro-jwt-redis实现用户登录的认证与授权(前后端分离)需要有一定shiro、jwt、redis、springboot基础
- ept技术_Intel虚拟化技术——EPT、VPID
- 【国内SEO大牛】网站统计显示被违禁词搜索进来原因
- 数据分析:大数据时代的必备技能之Power BI
- Hibiscus的脑机接口学习周报(2023/1/16~2023/1/22)
- java 生成纯色图片_java实现切图并且判断图片是不是纯色/彩色图片
- TVS管烧坏把其他电子产品烧毁,到底是谁的责任
- Jpg图片怎么变成gif动图?教你快速三步在线做gif