0
点赞
收藏
分享

微信扫一扫

MyBatis-Plus 之乐观锁插件


MyBatis-Plus 之乐观锁插件

适用场景

当要更新一条记录时,希望这条记录没有被别人更新过。

乐观锁实现方式:

  1. 取出记录时,获取当前​​version​​。
  2. 更新时,带上这个​​version​​。
  3. 执行更新时, ​​set version = newVersion where version = oldVersion​​。
  4. 如果​​version​​不对,就更新失败。

接下来,我们来演示MyBatis-Plus的乐观锁插件。

首先创建一个数据库表,如下图所示:

MyBatis-Plus 之乐观锁插件_maven


然后创建一个Spring Boot项目。

​pom.xml​​如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>org.kaven</groupId>
<artifactId>mybatis-plus</artifactId>
<version>1.0-SNAPSHOT</version>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
<relativePath/>
</parent>

<properties>
<java.version>1.8</java.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

​application.yml​​如下:

spring:
application:
name: mybatis-plus
datasource:
driver-class-name: com.mysql.jdbc.Driver
username: root
password: ITkaven@123
url: jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf-8&useSSL=false

server:
port: 8085

logging:
level:
root: warn
com.kaven.mybatisplus.dao: trace
pattern:
console: '%p%m%n'

实体类User:

package com.kaven.mybatisplus.entity;

import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;

@TableName("user")
@Data
public class User{

@TableId
private String id;

@TableField(value = "username")
private String username;

@TableField(value = "password")
private String password;

@TableField(value = "age")
private Integer age;

@Version
@TableField(value = "version")
private Integer version;
}

注解​​@Version​​不要忘记加上。

Mapper接口UserMapper:

package com.kaven.mybatisplus.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.kaven.mybatisplus.entity.User;
import org.springframework.stereotype.Component;


@Component
public interface UserMapper extends BaseMapper<User> {}

启动类:

package com.kaven.mybatisplus;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan(basePackages = "com.kaven.mybatisplus.dao")
public class AppRun {
public static void main(String[] args) {
SpringApplication.run(AppRun.class , args);
}
}

注解​​@MapperScan(basePackages = "com.kaven.mybatisplus.dao")​​一定要加上。

接下来是关键一步,我们需要将乐观锁插件加到MyBatis-Plus插件库中。

package com.kaven.mybatisplus.config;

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MybatisPlusConfig {

@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}

其实就是创建一个​​OptimisticLockerInnerInterceptor​​​实例通过​​addInnerInterceptor()​​​加到​​MybatisPlusInterceptor​​​中,再将​​MybatisPlusInterceptor​​​封装成​​bean​​。

先来看一看数据库的数据。

MyBatis-Plus 之乐观锁插件_后端_02


我们来测试一下乐观锁插件。

package com.kaven.mybatisplus.dao;

import com.kaven.mybatisplus.entity.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;


@RunWith(SpringRunner.class)
@SpringBootTest
public class LockerTest {

@Autowired
private UserMapper userMapper;

@Test
public void updateById(){
User user = userMapper.selectById("1");
int version = user.getVersion();

user.setPassword("new password");
user.setVersion(version);
int rows = userMapper.updateById(user);
System.out.println("影响行数: "+rows);
}
}

结果如下:

MyBatis-Plus 之乐观锁插件_maven_03


很显然结果是正确的,先查询,再更新,更新时帮我们加了版本号的条件。

特别说明

  • 支持的数据类型只有:​​int​​​、​​Integer​​​、​​long​​​、​​Long​​​、​​Date​​​、​​Timestamp​​​、​​LocalDateTime​​。
  • 整数类型下 ​​newVersion = oldVersion + 1​​。
  • ​newVersion​​​ 会回写到 ​​entity​​ 中。
  • 仅支持 ​​updateById(entity)​​​ 与 ​​update(entity, wrapper)​​ 方法。
  • update(entity, wrapper) 方法下, wrapper 不能复用。

上面是官网的说明。

在 ​​update(entity, wrapper)​​ 方法下, wrapper 不能复用,我们来测试一下。

package com.kaven.mybatisplus.dao;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.kaven.mybatisplus.entity.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;


@RunWith(SpringRunner.class)
@SpringBootTest
public class LockerTest {

@Autowired
private UserMapper userMapper;

@Test
public void update(){

LambdaQueryWrapper<User> userLambdaQueryWrapper = Wrappers.lambdaQuery();
userLambdaQueryWrapper.eq(User::getId , "1");

User user1 = userMapper.selectById("1");
int version1 = user1.getVersion();
user1.setPassword("new password"+version1);
user1.setVersion(version1);

int rows1 = userMapper.update(user1 , userLambdaQueryWrapper);
System.out.println("影响行数: "+rows1);

System.out.println("-------------------------------------------");

User user2 = userMapper.selectById("1");
int version2 = user2.getVersion();
user2.setPassword("new password"+version2);
user2.setVersion(version2);

int rows2 = userMapper.update(user2 , userLambdaQueryWrapper);
System.out.println("影响行数: "+rows2);
}
}

结果如下:

MyBatis-Plus 之乐观锁插件_后端_04


可以看到第一次更新是正常的,而第二次更新的​​sql​​​语句是有问题的,​​version​​​在​​WHERE​​条件中出现了两次,且值还不一样,所以这肯定是更新不到数据的。

UPDATE user SET username=?, password=?, age=?, version=? WHERE (id = ? AND version = ? AND version = ?)

所以,要记住,在 ​​update(entity, wrapper)​​ 方法下, wrapper 不能复用。

MyBatis-Plus的乐观锁插件就介绍到这里。

写博客是博主记录自己的学习过程,如果有错误,请指正,谢谢!



举报

相关推荐

0 条评论