mybatisplus使用OptimisticLockerInnerInterceptor实现版本号乐观锁
OptimisticLockerInnerInterceptor 介绍
当要更新一条记录的时候,希望这条记录没有被别人更新
乐观锁实现方式:
取出记录时,获取当前 version
更新时,带上这个 version
执行更新时, set version = newVersion where version = oldVersion
如果 version 不对,就更新失败。
创建项目
创建项目
引入依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.7</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
创建数据表
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`
(
id BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
age INT NULL DEFAULT NULL COMMENT '年龄',
email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
version INT not NULL DEFAULT 0 COMMENT '版本年龄',
PRIMARY KEY (id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
DELETE FROM user;
INSERT INTO user (id, name, age, email,version) VALUES
(1, 'Jone', 18, 'test1@baomidou.com',0),
(2, 'Jack', 20, 'test2@baomidou.com',0),
(3, 'Tom', 28, 'test3@baomidou.com',0),
(4, 'Sandy', 21, 'test4@baomidou.com',0),
(5, 'Billie', 24, 'test5@baomidou.com',0);
application.yml配置
server:
port: 8080
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://XXX:63306/user
username:
password:
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
项目结构
配置乐观锁拦截器
package com.sky.mybatisversiondemo.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;
}
}
创建实体类
version字段需要添加@Version注解表名是版本号字段
package com.sky.mybatisversiondemo.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.Version;
import lombok.Data;
@Data
public class User {
/**
* 主键ID
*/
@TableId(value = "id")
private Long id;
/**
* 姓名
*/
private String name;
/**
* 年龄
*/
private Integer age;
/**
* 邮箱
*/
private String email;
/**
* 版本号
*/
@Version
private Integer version;
}
创建mapper
package com.sky.mybatisversiondemo.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.sky.mybatisversiondemo.entity.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
创建service
这里利用了mybatisPlus的特性,提供了一些默认的查询。
UserService
package com.sky.mybatisversiondemo.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.sky.mybatisversiondemo.entity.User;
public interface UserService extends IService<User> {
}
UserServiceImpl
package com.sky.mybatisversiondemo.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sky.mybatisversiondemo.entity.User;
import com.sky.mybatisversiondemo.mapper.UserMapper;
import com.sky.mybatisversiondemo.service.UserService;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
创建返回包装类BaseResponse
package com.sky.mybatisversiondemo.vo;
import lombok.Data;
@Data
public class BaseResponse<T> {
protected int code = 0;
protected String message = "成功";
protected T data;
public BaseResponse(int code, String message) {
this.code = code;
this.message = message;
}
public static <T> BaseResponse of(T data) {
BaseResponse<T> response = new BaseResponse();
response.setData(data);
return response;
}
public BaseResponse() {
}
}
创建UserController
package com.sky.mybatisversiondemo.controller;
import com.sky.mybatisversiondemo.entity.User;
import com.sky.mybatisversiondemo.service.UserService;
import com.sky.mybatisversiondemo.vo.BaseResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/list")
public BaseResponse list(){
List<User> list = userService.list();
return BaseResponse.of(list);
}
@GetMapping("/ById")
public BaseResponse ById(Integer id){
User user = userService.getById(id);
if (user != null){
return BaseResponse.of(user);
}else {
return new BaseResponse(500,"fail");
}
}
/**
* 插入学生信息
* @param user
*/
@PostMapping("/insert")
public BaseResponse insertInfo(@RequestBody User user){
boolean save = userService.save(user);
if (save){
return BaseResponse.of(save);
}
return new BaseResponse(500,"fail");
}
/**
* 根据id更新学生表信息
* @param user
*/
@PutMapping("/update")
public BaseResponse updateById(@RequestBody User user){
boolean save = userService.updateById(user);
if (save){
return BaseResponse.of(save);
}
return new BaseResponse(500,"fail");
}
/**
* 根据id删除学生信息
* @param id
*/
@DeleteMapping("/delete")
public BaseResponse deleteById(String id){
boolean b = userService.removeById(id);
if (b){
return BaseResponse.of(b);
}
return new BaseResponse(500,"fail");
}
}
测试
查询
修改
修改是自动增加版本号,并且会增加版本号的判断,只有版本号一致才能修改成功。
日志
==> Preparing: UPDATE user SET name=?, age=?, email=?, version=? WHERE id=? AND version=?
==> Parameters: Jone(String), 18(Integer), test1@baomidou.com(String), 1(Integer), 1(Long), 0(Integer)
<== Updates: 1
修改后再查询
此时版本号增加到1
再次按版本号0修改
修改失败,因为版本号已经增加到了1,实现了乐观锁功能。
如果开发中遇到这种因为乐观锁修改失败的,则可以直接报错,或者再次查询数据后重试。推荐直接报错,修改失败,请重试。
修改时不传入版本号
则可以直接修改成功 ,但是修改后版本号不会增加,不推荐不传入版本号的修改。
日志
==> Preparing: UPDATE user SET name=?, age=?, email=? WHERE id=?
==> Parameters: Jone(String), 18(Integer), test1@baomidou.com(String), 1(Long)
<== Updates: 1