使用乐观锁进行数据更新
1、基本介绍
乐观锁的应用场景是当要更新一条记录的时候,希望这条记录没有被别人更新。
注意:
目前乐观锁仅支持 updateById(id) 与 update(entity, wrapper) 方法 在 update(entity,
wrapper) 方法下,wrapper 不能复用!!!
乐观锁实现方式如下:
取出记录时,获取当前 version 执行更新时,带上这个 version,即 set version = new Version
where version = old Version 如果 version 不对,就更新失败
MyBatis-Plus 是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。它内置了对乐观锁的支持。乐观锁主要是用来控制并发操作,其核心思想是假设数据在更新过程中不会被其他线程修改,因此它不会像悲观锁那样在数据处理过程中进行加锁,而是通过一个“版本号”或者是“时间戳”进行控制。
为了在 MyBatis-Plus 中使用乐观锁,你需要以下几个步骤:
- 添加乐观锁插件:
首先,需要在你的 MyBatis-Plus 配置类中添加乐观锁插件的配置。
import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.mybatis.spring.annotation.MapperScan;
@Configuration
@MapperScan("com.example.mapper")
public class MybatisPlusConfig {
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
- 在实体类中添加版本号字段:
在你的实体类中添加一个用于控制乐观锁的版本号字段,通常是version
,并且在该字段上添加@Version
注解。
import com.baomidou.mybatisplus.annotation.Version;
public class User {
private Long id;
private String name;
private String email;
@Version
private Integer version;
// 省略其他字段的getter和setter...
// 注意添加version字段的getter和setter
public Integer getVersion() {
return version;
}
public void setVersion(Integer version) {
this.version = version;
}
}
- 执行更新操作:
当执行更新操作时,MyBatis-Plus 会检查实体类中带有@Version
注解的字段,基于这个字段来自动构建乐观锁的 SQL 语句。
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.example.entity.User;
import com.example.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
public class UserService {
@Autowired
private UserMapper userMapper;
public void updateUserById(Long userId) {
User user = userMapper.selectById(userId);
if (user != null) {
user.setEmail("newemail@example.com");
// 当更新时会根据version字段自动执行乐观锁检查
int result = userMapper.updateById(user);
if (result == 0) {
throw new OptimisticLockingFailureException("更新失败,数据可能已被其他用户修改");
}
}
}
}
在这个例子中,当调用updateById
方法时,MyBatis-Plus 会在 SQL 更新语句中加入一个条件来检查version
字段,确保这个字段的值与数据库中的值一致,然后在更新成功时自动将这个字段的值加一。如果在更新过程中version
字段的值已经被其他线程修改,那么这次更新操作将会失败,result
将会是0。
使用乐观锁需要注意的是,每次更新操作都需要重新查询数据库以确保version
字段的值是最新的,否则可能会导致更新失败。此外,乐观锁并不能完全保证数据的一致性,在高并发的场合下可能仍然会出现问题,比如“ABA”问题,因此在这些场景下可能需要其他的并发控制手段。