Mybatis-plus乐观锁

server/2024/9/23 9:21:52/

为什么要用锁

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

例如有条数据   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);}
}


http://www.ppmy.cn/server/98311.html

相关文章

概述amr 机器人软硬组成

AMR&#xff08;Autonomous Mobile Robot&#xff0c;自主移动机器人&#xff09;是一种能够在没有人为干预的情况下&#xff0c;使用各种传感器和算法在环境中导航和执行任务的机器人。 AMR的组成主要包括以下几个部分&#xff1a; 1. 底盘系统&#xff1a; 驱动系统&#x…

Excel中不能通过方向键移动单元格都是这个按键的锅!

通常&#xff0c;在Excel中一个单元格输入文字后&#xff0c;会使用方向键移到另一个单元格。但突然某次操作时&#xff0c;方向键不好用了&#xff0c;按下方向键是整个表格左右移动&#xff0c;单元格定位不变&#xff0c;这太影响效率了。 后来发现原来是Scrooll Lock这个按…

为啥https比http慢

Https有ssl的握手 HTTP没有 HTTPS TCP 和HTTP 的TCP 时间差不是很大 HTTPS请求中,ssl所占的时间比例是请求时间总和93.37%, HTTPS请求中,ssl的请求会是tcp请求的14倍,而HTTP中没有这个问题 建议:对安全要求不是很高的,不要使用https请求 图例

悠易科技周文彪:创始人专注度很重要,一旦战略分散无法形成合力 | 中国广告营销行业资本报告深访④

周文彪&#xff08;悠易科技CEO&#xff09; 问&#xff1a;近年来广告营销行业主要的融资事件发生在营销技术领域。您对此有何评论&#xff1f; Roy&#xff1a;Adtech最早从2007年前后开始发展&#xff0c;差不多十年的时间&#xff0c;因为广告技术帮助企业成长&#xff0c…

fs.writeFile的encoding参数深入解析:掌握Node.js文件写入编码

在Node.js的fs.writeFile方法中&#xff0c;encoding参数是一个可选参数&#xff0c;用于指定写入文件时数据的编码格式。下面将深入解析encoding参数的使用及其重要性。 encoding参数的基本作用 当使用fs.writeFile方法写入文件时&#xff0c;如果数据是字符串类型&#xff…

直接插入排序(代码实现及其复杂度分析)

给定你一个长度为 nn 的整数数列。 请你使用插入排序对这个数列按照从小到大进行排序。 并将排好序的数列按顺序输出。 输入格式 输入共两行&#xff0c;第一行包含整数 nn。 第二行包含 nn 个整数&#xff08;所有整数均在 1∼1091∼109 范围内&#xff09;&#xff0c;表…

QT 布局管理器之QHBoxLayout

文章目录 概述.ui来看看Cmain.cpp运行 小结 概述 QHBoxLayout&#xff0c;在QT中是一个布局文件&#xff0c;而且相对来说还是比较简单的。接下来看下。 .ui 先看下在qt design中是如何用的&#xff0c;如下图&#xff1a; 就是这个布局文件&#xff0c;是一个xml的文件&am…

文件与进程

理解文件&#xff1a; 操作文件的本质是进程在操作文件&#xff01;这是进程和文件的关系&#xff01; 如何理解文件&#xff1f; 文件在未打开之前是存在磁盘中的&#xff0c;而磁盘是在外设上的&#xff0c;也就是硬件上的&#xff0c;所以向文件中写入&#xff0c;本质上…