一、乐观锁
参考自:乐观锁插件
意图:
当要更新一条记录的时候,希望这条记录没有被别人更新
乐观锁实现方式:
取出记录时,获取当前version
更新时,带上这个version
执行更新时, set version = newVersion where version = oldVersion
如果version不对,就更新失败
1.新增字段version
还是使用之前的user表,在user表中新增一个字段"version",类型为int,默认值为"1"。
2.修改实体类
修改实体类,给实体类增加上version属性,并且在该属性上增加@Version注解。
@Version注解描述:乐观锁注解、标记 @Verison 在字段上
@Data
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
private Integer age;
private String email;
/** 字段自动填充策略 */
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.UPDATE)
private Date updateTime;
/** 乐观锁 */
@Version
private int version;
}
3.插件配置(注册bean)
创建一个配置类MybatisPlusConfig(mybatis-plus的配置)。
然后进行乐观锁的插件配置。
/**
* mybatis-plus 配置
*
* 注解:@Configuration 代表这是一个配置类
* 注解:@EnableTransactionManagement 开启事务管理(默认就是开启的)
* 注解:@MapperScan 代表扫描该包下的mapper接口(这样启动类就不需要加这个了)
* @author ChangSheng
* @date 2020-04-24
*/
@Configuration
@EnableTransactionManagement
@MapperScan("com.slensoft.mp.samples.quickstart.mapper")
public class MybatisPlusConfig {
/** 乐观锁插件配置 */
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor(){
return new OptimisticLockerInterceptor();
}
}
4.测试
注意:id为"1"的用户,他的version如果为"null",需要手动给他填写1。
4.1 单线程测试
在单线程下会一直是成功的。如下测试代码
/** 乐观锁测试成功(单线程) */
@Test
public void testLock01() {
// 1.查询用户
User user = userMapper.selectById(1L);
// 2.修改
user.setName("testLock01");
// 3.执行
userMapper.updateById(user);
}
4.2 多线程测试
模拟多线程环境。
“模拟线程1”在操作时,“模拟线程2”插队进行了操作,此时如果没有乐观锁,那么最后一句更新操作将覆盖掉“模拟线程2”的操作。
此时每次运行如下代码,会发现version每次都会自增1。
/** 乐观锁测试失败(多线程) */
@Test
public void testLock02() {
// 模拟线程1操作
User user = userMapper.selectById(1L);
user.setName("testLock02 - 111");
// 模拟线程2操作(模拟另一个用户,他插队了线程1的操作)
User user2 = userMapper.selectById(1L);
user2.setName("testLock02 - 222");
userMapper.updateById(user2);
// 如果没有乐观锁,下面语句将会覆盖“模拟线程2”的操作。有乐观锁则不会。
userMapper.updateById(user);
}
所以,多线程环境下,一定要加锁。