跳至主要內容

乐观锁版本号

xuejmnet大约 4 分钟

版本号

easy-query提供了自动版本号功能,可以保证在高并发下数据一致性更新的问题。

相关配置

noVersionError默认为true当对象有Version字段并且更新修改不存在version字段将会报错,可以通过noVersionError或者noVersionIgnore来配置

demo数据


@Data
@Table(value = "t_sys_user_version")
public class SysUserVersionLong {
    @Column(primaryKey = true)
    private String id;
    private String username;
    private String phone;
    private String idCard;
    private String address;
    /**
     * 创建时间;创建时间
     */
    private LocalDateTime createTime;
    @Version(strategy = VersionLongStrategy.class)
    private Long version;
}

Api

EasyVersionStrategy

方法名参数描述
nextVersion当前版本信息和对应的属性和对象信息返回更新后的版本信息

默认实现系统提供

  • VersionIntStrategy列对象为int,next version为当前version+1
  • VersionLongStrategy列对象为long,next version为当前version+1
  • VersionUUIDStrategy列对象为string,next version为当UUID.randomUUID().toString().replaceAll("-","")
  • VersionTimestampStrategy列对象为long,next version为当System.currentTimeMillis() (不推荐)

测试数据

添加测试数据


//插入
SysUserVersionLong sysUserVersionLong = new SysUserVersionLong();
sysUserVersionLong.setId(id);
sysUserVersionLong.setCreateTime(LocalDateTime.now());
sysUserVersionLong.setVersion(1L);
sysUserVersionLong.setUsername("username"+id);
sysUserVersionLong.setPhone("13232323232");
sysUserVersionLong.setIdCard("0000000000");
sysUserVersionLong.setAddress("浙江省绍兴市越城区城市广场");
long l = easyQuery.insertable(sysUserVersionLong).executeRows();
Assert.assertEquals(1,l);


==> Preparing: INSERT INTO t_sys_user_version (`id`,`username`,`phone`,`id_card`,`address`,`create_time`,`version`) VALUES (?,?,?,?,?,?,?) 
==> Parameters: 1(String),username1(String),13232323232(String),0000000000(String),浙江省绍兴市越城区城市广场(String),2023-04-08T13:49:10.037(LocalDateTime),1(Long)
<== Total: 1


//查询
SysUserVersionLong sysUserVersionLong1 = easyQuery.queryable(SysUserVersionLong.class)
        .whereById(id).firstOrNull();
Assert.assertNotNull(sysUserVersionLong1);


==> Preparing: SELECT t.`id`,t.`username`,t.`phone`,t.`id_card`,t.`address`,t.`create_time`,t.`version` FROM t_sys_user_version t WHERE t.`id` = ? LIMIT 1
==> Parameters: 1(String)
<== Total: 1, Query Use: 3(ms)

实体更新

long l2 = easyQuery.updatable(sysUserVersionLong1).executeRows();
Assert.assertEquals(1,l2);


==> Preparing: UPDATE t_sys_user_version SET `username` = ?,`phone` = ?,`id_card` = ?,`address` = ?,`create_time` = ?,`version` = ? WHERE `version` = ? AND `id` = ?
==> Parameters: username1(String),13232323232(String),0000000000(String),浙江省绍兴市越城区城市广场(String),2023-04-08T13:49:10(LocalDateTime),2(Long),1(Long),1(String)
<== Total: 1

表达式更新

表达式删除必须要添加withVersion否则将不会使用行版本更新,并且如果配置或者没有配置noVersionError(默认true)将会报错,可以通过noVersionIgnore来忽略

//whereById主键更新
long l2 = easyQuery.updatable(SysUserVersionLong.class)
        .set(SysUserVersionLong::getPhone, "123")
        .whereById(id)
        .noVersionIgnore()
        .executeRows();
Assert.assertEquals(1,l2);


==> Preparing: UPDATE t_sys_user_version SET `phone` = ? WHERE `id` = ?
==> Parameters: 123(String),2(String)
<== Total: 1

//where表达式更新
long l3 = easyQuery.updatable(SysUserVersionLong.class)
        .noVersionIgnore()
        .set(SysUserVersionLong::getPhone, "123")
        .where(o->o.eq(SysUserVersionLong::getId,id))
        .executeRows();
Assert.assertEquals(1,l3);

==> Preparing: UPDATE t_sys_user_version SET `phone` = ? WHERE `id` = ?
==> Parameters: 123(String),2(String)
<== Total: 1

//表达式更新只需要添加withVersion那么就可以针对当前version进行版本控制
long l4 = easyQuery.updatable(SysUserVersionLong.class)
        .set(SysUserVersionLong::getPhone, "123")
        .withVersion(1L)
        .where(o->o.eq(SysUserVersionLong::getId,id))
        .executeRows();
Assert.assertEquals(1,l4);


==> Preparing: UPDATE t_sys_user_version SET `phone` = ?,`version` = ? WHERE `version` = ? AND `id` = ?
==> Parameters: 123(String),2(Long),1(Long),2(String)
<== Total: 1

逻辑删除加版本号

逻辑删除情况下删除数据将会对数据列进行行版本追加,并且where条件也会追加版本号,如果禁用逻辑删,那么行版本的追加只会纯在与where条件的追加,并且如果配置或者没有配置noVersionError(默认true)将会报错,可以通过noVersionIgnore来忽略

@Data
@Table(value = "t_sys_user_version_del")
public class SysUserVersionLongLogicDel {
    @Column(primaryKey = true)
    private String id;
    private String username;
    private String phone;
    private String idCard;
    private String address;
    /**
     * 创建时间;创建时间
     */
    private LocalDateTime createTime;
    @Version(strategy = VersionLongStrategy.class)
    private Long version;

    @LogicDelete(strategy = LogicDeleteStrategyEnum.BOOLEAN)
    private Boolean deleted;
}

实体对象删除

//插入
SysUserVersionLongLogicDel sysUserVersionLongLogicDel = new SysUserVersionLongLogicDel();
sysUserVersionLongLogicDel.setId(id);
sysUserVersionLongLogicDel.setCreateTime(LocalDateTime.now());
sysUserVersionLongLogicDel.setVersion(1L);
sysUserVersionLongLogicDel.setUsername("username"+id);
sysUserVersionLongLogicDel.setPhone("13232323232");
sysUserVersionLongLogicDel.setIdCard("0000000000");
sysUserVersionLongLogicDel.setAddress("浙江省绍兴市越城区城市广场");
sysUserVersionLongLogicDel.setDeleted(false);
long l = easyQuery.insertable(sysUserVersionLongLogicDel).executeRows();
Assert.assertEquals(1,l);


==> Preparing: INSERT INTO t_sys_user_version_del (`id`,`username`,`phone`,`id_card`,`address`,`create_time`,`version`,`deleted`) VALUES (?,?,?,?,?,?,?,?) 
==> Parameters: 4(String),username4(String),13232323232(String),0000000000(String),浙江省绍兴市越城区城市广场(String),2023-04-08T14:01:58.315(LocalDateTime),1(Long),false(Boolean)
<== Total: 1

//逻辑删除
long l2 = easyQuery.deletable(sysUserVersionLongLogicDel).executeRows();
Assert.assertEquals(1,l2);


==> Preparing: UPDATE t_sys_user_version_del SET `deleted` = ?,`version` = ? WHERE `deleted` = ? AND `version` = ? AND `id` = ?
==> Parameters: true(Boolean),2(Long),false(Boolean),1(Long),4(String)
<== Total: 1

表达式删除

表达式删除必须要添加withVersion否则将不会使用行版本删除

SysUserVersionLongLogicDel sysUserVersionLongLogicDel = new SysUserVersionLongLogicDel();
sysUserVersionLongLogicDel.setId(id);
sysUserVersionLongLogicDel.setCreateTime(LocalDateTime.now());
sysUserVersionLongLogicDel.setVersion(1L);
sysUserVersionLongLogicDel.setUsername("username"+id);
sysUserVersionLongLogicDel.setPhone("13232323232");
sysUserVersionLongLogicDel.setIdCard("0000000000");
sysUserVersionLongLogicDel.setAddress("浙江省绍兴市越城区城市广场");
sysUserVersionLongLogicDel.setDeleted(false);
long l = easyQuery.insertable(sysUserVersionLongLogicDel).executeRows();
Assert.assertEquals(1,l);


==> Preparing: INSERT INTO t_sys_user_version_del (`id`,`username`,`phone`,`id_card`,`address`,`create_time`,`version`,`deleted`) VALUES (?,?,?,?,?,?,?,?) 
==> Parameters: 5(String),username5(String),13232323232(String),0000000000(String),浙江省绍兴市越城区城市广场(String),2023-04-08T14:04:11.275(LocalDateTime),1(Long),false(Boolean)
<== Total: 1


long l2 = easyQuery.deletable(SysUserVersionLongLogicDel.class)
        .withVersion(1L)
        .whereById(id).executeRows();
Assert.assertEquals(1,l2);


==> Preparing: UPDATE t_sys_user_version_del SET `deleted` = ?,`version` = ? WHERE `deleted` = ? AND `version` = ? AND `id` = ?
==> Parameters: true(Boolean),2(Long),false(Boolean),1(Long),5(String)
<== Total: 1



long l2 = easyQuery.deletable(SysUserVersionLongLogicDel.class)
        .noVersionIgnore()
        .whereById(id).executeRows();
Assert.assertEquals(1,l2);


==> Preparing: UPDATE t_sys_user_version_del SET `deleted` = ? WHERE `deleted` = ? AND `id` = ?
==> Parameters: true(Boolean),2(Long),false(Boolean),1(Long),5(String)
<== Total: 1
上次编辑于:
贡献者: Hoysing