当前位置: 首页 > news >正文

Mybatis-plus乐观锁

为什么要用锁

原因是当两个线程并发修改同一条数据时候

例如有条数据   id   1      count(金额/数量)   500   

有两个线程都在查询数据库  查出来都是  1        500

现在两个线程都要修改这条数据   在原来基础上+20  和+30

那么理论来讲应该是550

可是实际有可能是530

原因就是查出来时候都是500

第一个线程加了20  变成520

可是第二个线程查出来也是500  加了30

并发安全问题不是次次发生,是偶尔很小几率发生的事,但是这个几率是确实存在的

Mybatis-plus通过乐观锁可以对这个问题进行处理

加了一个version  版本号

每次更新的时候会将版本号自动+1

当两个线程都在查   查出来   1    500

第一个线程去update的时候   顺手将版本号加了1

例如   update t_test set count=520,set version+=1 where id=xxxxx and version=x

而此时第二个线程去update的时候  由于原先查出来版本号还是原来的  会导致更新不成功  那么在事务的驱动下,全部回滚

官方文档:乐观锁插件 | MyBatis-Plus

关于使用版本  文档上写着SpringBoot2  和SpringBoot3  分别使用的版本

示例demo

<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-spring-boot3-starter</artifactId><version>3.5.7</version>
</dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version>
</dependency>

 乐观锁配置

package com.example.demo.config;import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** @author hrui* @date 2024/8/6 2:38*/
@Configuration
@MapperScan({"com.example.demo.mapper"})
public class MybatisPlusConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());return interceptor;}
}

持久层

package com.example.demo.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.pojo.TTest;/*** @author hrui* @date 2024/8/6 2:39*/
public interface TTestMapper extends BaseMapper<TTest> {
}

业务接口

package com.example.demo.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.example.demo.pojo.TTest;/*** @author hrui* @date 2024/8/6 2:41*/
public interface TTestService extends IService<TTest> {}

业务实现

package com.example.demo.service;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.demo.mapper.TTestMapper;
import com.example.demo.pojo.TTest;
import org.springframework.stereotype.Service;/*** @author hrui* @date 2024/8/6 2:43*/
@Service
public class TTestServiceImpl extends ServiceImpl<TTestMapper, TTest> implements TTestService {}

实体类

package com.example.demo.pojo;import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.Version;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;/*** @author hrui* @date 2024/8/6 2:40*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class TTest {private Long id;private Integer count;@Versionprivate Integer version;
}

application.properties

spring.application.name=demo# 数据库连接配置
spring.datasource.url=jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.username=xxxx
spring.datasource.password=xxxxxx
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver# MyBatis-Plus 配置
mybatis-plus.mapper-locations=classpath:/mappers/**/*.xml#配置实体类包
mybatis-plus.type-aliases-package=com.example.demo.pojo# 开启驼峰命名转换
mybatis-plus.configuration.map-underscore-to-camel-case=true# 打印执行的 SQL 语句
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

测试类

package com.example.demo;import com.example.demo.mapper.TTestMapper;
import com.example.demo.pojo.TTest;
import com.example.demo.service.TTestService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
class DemoApplicationTests {@Testvoid contextLoads() {}@Autowiredprivate TTestService tTestService;@Autowiredprivate TTestMapper tTestMapper;@Testpublic void test(){boolean save = tTestService.save(new TTest(null, 200, null));System.out.println(save);}@Testpublic void test2(){TTest byId = tTestService.getById(1820548023958319106L);TTest byId2 = tTestService.getById(1820548023958319106L);byId.setCount(201);byId2.setCount(202);tTestService.updateById(byId);tTestService.updateById(byId2);}
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 二维数据平滑,滤波方法比较:移动平均平滑、中值滤波、指数加权移动平均、Savitzky-Golay、高斯滤波、卡尔曼滤波
  • Apple Vision Pro 游戏开发:挑战与反思
  • js中的全局函数有这些
  • 使用 Python 制作一个属于自己的 AI 搜索引擎
  • CSS实现元素hover时背景色拉伸渐变
  • C++入门1
  • Python处理Redis
  • 【数据结构】排序 —— 快速排序(quickSort)
  • 鸿蒙应用服务开发【钱包服务(ArkTS)】
  • Linux 的 Port Knocking 端口碰撞(端口敲门)
  • C++从入门到入土(四)--日期类的实现
  • OpenAI 称其在发布检测 ChatGPT 写作的工具时采取“审慎态度”
  • Java编程常见问题解析与代码示例
  • 基于whisper流式语音识别
  • 【Kubernetes】应用的部署(一):金丝雀部署
  • [译]CSS 居中(Center)方法大合集
  • 【跃迁之路】【735天】程序员高效学习方法论探索系列(实验阶段492-2019.2.25)...
  • niucms就是以城市为分割单位,在上面 小区/乡村/同城论坛+58+团购
  • Node 版本管理
  • PHP 使用 Swoole - TaskWorker 实现异步操作 Mysql
  • Sublime text 3 3103 注册码
  • 构造函数(constructor)与原型链(prototype)关系
  • 基于Javascript, Springboot的管理系统报表查询页面代码设计
  • 记一次和乔布斯合作最难忘的经历
  • 聚簇索引和非聚簇索引
  • 爬虫进阶 -- 神级程序员:让你的爬虫就像人类的用户行为!
  • 扫描识别控件Dynamic Web TWAIN v12.2发布,改进SSL证书
  • 小程序 setData 学问多
  • 要让cordova项目适配iphoneX + ios11.4,总共要几步?三步
  • ​​​​​​​STM32通过SPI硬件读写W25Q64
  • #Z2294. 打印树的直径
  • $NOIp2018$劝退记
  • (3) cmake编译多个cpp文件
  • (LeetCode) T14. Longest Common Prefix
  • (MonoGame从入门到放弃-1) MonoGame环境搭建
  • (附源码)ssm高校社团管理系统 毕业设计 234162
  • (附源码)ssm经济信息门户网站 毕业设计 141634
  • (附源码)基于SpringBoot和Vue的厨到家服务平台的设计与实现 毕业设计 063133
  • (六)DockerCompose安装与配置
  • (算法)硬币问题
  • (转)h264中avc和flv数据的解析
  • .axf 转化 .bin文件 的方法
  • .gitignore不生效的解决方案
  • .NET Core 项目指定SDK版本
  • .net core使用RPC方式进行高效的HTTP服务访问
  • .NET Standard 的管理策略
  • .NET/C# 使用 SpanT 为字符串处理提升性能
  • .Net多线程总结
  • /*在DataTable中更新、删除数据*/
  • @ConditionalOnProperty注解使用说明
  • @SuppressWarnings注解
  • [.NET]桃源网络硬盘 v7.4
  • [240527] 谷歌 CEO 承认 AI 编造虚假信息问题难解(此文使用 @gemini 命令二次创作)| ICQ 停止运作
  • [AIGC] Redis基础命令集详细介绍
  • [BZOJ 4129]Haruna’s Breakfast(树上带修改莫队)