【MyBatis-Plus】(4)乐观锁

【MyBatis-Plus】(4)乐观锁

一、乐观锁

参考自:乐观锁插件

意图:

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

乐观锁实现方式:

取出记录时,获取当前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.shengjava.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);
    }

所以,多线程环境下,一定要加锁。