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 {
    @Bean
    public 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;

    @Version
    private 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 {

    @Test
    void contextLoads() {
    }


    @Autowired
    private TTestService tTestService;

    @Autowired
    private TTestMapper tTestMapper;
    @Test
    public void test(){
        boolean save = tTestService.save(new TTest(null, 200, null));
        System.out.println(save);

    }

    @Test
    public void test2(){
        TTest byId = tTestService.getById(1820548023958319106L);
        TTest byId2 = tTestService.getById(1820548023958319106L);
        byId.setCount(201);
        byId2.setCount(202);

        tTestService.updateById(byId);
        tTestService.updateById(byId2);

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hrui0706

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值