mybitsPlus乐观锁@Version案例测试,发现有失效的情况
一、案例
("NEWTABLE_TEST")
(value = "BusBalance对象", description = "额度表")
public class NewTableTest {
private static final long serialVersionUID = 1L;
(value = "ID")
private String id;
private Integer version;
private String remark;
}
1、写入一条数据进行测试,此时版本号号为0。
String id = "1";
NewTableTest newTableTest = new NewTableTest();
newTableTest.setId(id);
newTableTest.setVersion(0);
newTableTest.setRemark("入库第一次");
testMapper.insert(newTableTest);
NewTableTest newTableTest1 = testMapper.selectById(id);
System.out.println("入库第一次:"+newTableTest1);
//入库第一次:NewTableTest(id=1, version=0, remark=入库第一次)
2、不设置version字段测试,更新成功,写入后版本号为1。
newTableTest.setRemark("修改第一次");
int i1 = testMapper.updateById(newTableTest1);
// Preparing: UPDATE NEWTABLE_TEST SET version=?, remark=? WHERE ID=? AND version=?
// Parameters: 1(Integer), 修改第一次(String), 1(String), 0(Integer)
System.out.println("修改第一次不设置version成功/失败:"+ (i1 == 0 ? false: true));
//修改第一次不设置version成功/失败:true
NewTableTest newTableTest2 = testMapper.selectById(id);
System.out.println("修改第一次不设置version:"+newTableTest2);
//修改第一次不设置version:NewTableTest(id=1, version=1, remark=修改第一次)
3、查询出的实体数据版本号+1=2进行测试,更新失败,版本号为1。
newTableTest2.setVersion(newTableTest2.getVersion() + 1);
newTableTest2.setRemark("修改第2次");
int i2 = testMapper.updateById(newTableTest2);
// ==> Preparing: UPDATE NEWTABLE_TEST SET version=?, remark=? WHERE ID=? AND version=?
//==> Parameters: 3(Integer), 修改第2次(String), 1(String), 2(Integer)
System.out.println("修改第2次设置version+1成功/失败:"+ (i2 == 0 ? false: true));
//修改第2次设置version成功/失败:false
NewTableTest newTableTest3 = testMapper.selectById(id);
System.out.println("修改第2次设置version+1:"+newTableTest3);
//修改第2次设置version+1:NewTableTest(id=1, version=1, remark=修改第一次)
4、查询出的实体数据版本号随意写入数字进行测试,更新失败,版本号为1。
newTableTest3.setVersion(9);
newTableTest3.setRemark("修改第3次");
int i3 = testMapper.updateById(newTableTest3);
//==> Preparing: UPDATE NEWTABLE_TEST SET version=?, remark=? WHERE ID=? AND version=?
//==> Parameters: 10(Integer), 修改第3次(String), 1(String), 9(Integer)
System.out.println("修改第3次设置version成功/失败:"+ (i3 == 0 ? false: true));
//修改第3次设置version成功/失败:false
NewTableTest newTableTest4 = testMapper.selectById(id);
System.out.println("修改第3次设置version:"+newTableTest4);
//修改第3次设置version:NewTableTest(id=1, version=1, remark=修改第一次)
5、使用update进行更新,实体为null,注解失效,更新成功(乐观锁需手动设置),版本号为9。
LambdaUpdateWrapper<NewTableTest> set = new LambdaUpdateWrapper<NewTableTest>()
.eq(NewTableTest::getVersion, newTableTest4.getVersion())
.eq(NewTableTest::getId, id)
.set(NewTableTest::getVersion,9)
.set(NewTableTest::getRemark,"测试");
int update = testMapper.update(null, set);
System.out.println("测试成功/失败:"+ (update == 0 ? false: true));
//测试成功/失败:true
NewTableTest newTableTest5 = testMapper.selectById(id);
System.out.println("测试:"+newTableTest5);
//测试:NewTableTest(id=1, version=9, remark=测试)
6、使用update进行更新,实体为不为null,注解生效,更新失败,版本号为9。
LambdaUpdateWrapper<NewTableTest> set2 = new LambdaUpdateWrapper<NewTableTest>()
.eq(NewTableTest::getVersion, newTableTest5.getVersion())
.eq(NewTableTest::getId, id);
newTableTest5.setVersion(20);
newTableTest5.setRemark("更新实体测试");
int update1 = testMapper.update(newTableTest5, set2);
System.out.println("更新实体测试成功/失败:"+ (update1 == 0 ? false: true));
//更新实体测试成功/失败:false
上面代码发现version条件再次多了一个,可能是注解生效了,把设置版本号代码注释掉。
LambdaUpdateWrapper<NewTableTest> set2 = new LambdaUpdateWrapper<NewTableTest>()
// .eq(NewTableTest::getVersion, newTableTest5.getVersion())
.eq(NewTableTest::getId, id);
newTableTest5.setVersion(20);
newTableTest5.setRemark("更新实体测试");
int update1 = testMapper.update(newTableTest5, set2);
System.out.println("更新实体测试成功/失败:"+ (update1 == 0 ? false: true));
更新实体测试成功/失败:false
NewTableTest newTableTest6 = testMapper.selectById(id);
System.out.println("更新实体测试:"+newTableTest6);
更新实体测试:NewTableTest(id=1, version=9, remark=测试)
注解生效,并且和上面一直,在设置的实体版本号+1进行更新。
7、实体为new出的实体,不设置任何值。注解失效,更新成功(乐观锁需手动设置),版本号更新为11。
LambdaUpdateWrapper<NewTableTest> set22 = new LambdaUpdateWrapper<NewTableTest>()
.eq(NewTableTest::getVersion, newTableTest6.getVersion())
.eq(NewTableTest::getId, id)
.set(NewTableTest::getVersion,11)
.set(NewTableTest::getRemark,"实体不设值测试");
int update2 = testMapper.update(new NewTableTest(), set22);
//Preparing: UPDATE NEWTABLE_TEST SET version=?,remark=? WHERE (version = ? AND ID = ?)
// ==> Parameters: 11(Integer), 实体不设值测试(String), 9(Integer), 1(String)
System.out.println("实体不设值测试成功/失败:"+ (update2 == 0 ? false: true));
//更新实体测试成功/失败:true
NewTableTest newTableTest55 = testMapper.selectById(id);
System.out.println("实体不设值测试成功:"+newTableTest55);
//实体不设值测试成功:NewTableTest(id=1, version=11, remark=实体不设值测试)
二、综上总结
1、mybitsPlus乐观锁@Version根据实体查询或者设置的值进行+1为set的值,实体版本号的值(查询出或者被重设)为会被默认为条件查询值。
所以实体设置乐观锁注解的值,查询出的该值,不能变更为其他值,否则会导致更新失败。
/**
* newTableTest3.setVersion(9);
* newTableTest3.setRemark("修改第3次");
* int i3 = testMapper.updateById(newTableTest3);
* Preparing: UPDATE NEWTABLE_TEST SET version=?, remark=? WHERE ID=? AND version=?
* Parameters: 10(Integer), 修改第3次(String), 1(String), 9(Integer)
*/
//实体设置的值为9,sql则使用该值当条件。当前值+1为set的值。
2、@Version注解会有失效的情况。
使用updateById注解不会失效。
使用update如果实体为null,或者不赋值会导致注解失效。
3、尽量避免使用@Version注解,自行控制版本号。如果注解生效,但是又手动控制版本号会导致更新失败,不注意会导致数据问题。
三、测试demo
("NEWTABLE_TEST")
(value = "BusBalance对象", description = "额度表")
public class NewTableTest {
private static final long serialVersionUID = 1L;
(value = "ID")
private String id;
private Integer version;
private String remark;
}
package com.ynyc.business.controller;
("api/test")
public class TestController {
private NewTableTestMapper testMapper;
("index")
public R<Object> index() {
String id = "1";
NewTableTest newTableTest = new NewTableTest();
newTableTest.setId(id);
newTableTest.setVersion(0);
newTableTest.setRemark("入库第一次");
testMapper.insert(newTableTest);
NewTableTest newTableTest1 = testMapper.selectById(id);
System.out.println("入库第一次:"+newTableTest1);
//入库第一次:NewTableTest(id=1, version=0, remark=入库第一次)
newTableTest.setRemark("修改第一次");
int i1 = testMapper.updateById(newTableTest1);
// Preparing: UPDATE NEWTABLE_TEST SET version=?, remark=? WHERE ID=? AND version=?
// Parameters: 1(Integer), 修改第一次(String), 1(String), 0(Integer)
System.out.println("修改第一次不设置version成功/失败:"+ (i1 == 0 ? false: true));
//修改第一次不设置version成功/失败:true
NewTableTest newTableTest2 = testMapper.selectById(id);
System.out.println("修改第一次不设置version:"+newTableTest2);
//修改第一次不设置version:NewTableTest(id=1, version=1, remark=修改第一次)
newTableTest2.setVersion(newTableTest2.getVersion() + 1);
newTableTest2.setRemark("修改第2次");
int i2 = testMapper.updateById(newTableTest2);
// ==> Preparing: UPDATE NEWTABLE_TEST SET version=?, remark=? WHERE ID=? AND version=?
//==> Parameters: 3(Integer), 修改第2次(String), 1(String), 2(Integer)
System.out.println("修改第2次设置version+1成功/失败:"+ (i2 == 0 ? false: true));
//修改第2次设置version成功/失败:false
NewTableTest newTableTest3 = testMapper.selectById(id);
System.out.println("修改第2次设置version+1:"+newTableTest3);
//修改第2次设置version+1:NewTableTest(id=1, version=1, remark=修改第一次)
newTableTest3.setVersion(9);
newTableTest3.setRemark("修改第3次");
int i3 = testMapper.updateById(newTableTest3);
//==> Preparing: UPDATE NEWTABLE_TEST SET version=?, remark=? WHERE ID=? AND version=?
//==> Parameters: 10(Integer), 修改第3次(String), 1(String), 9(Integer)
System.out.println("修改第3次设置version成功/失败:"+ (i3 == 0 ? false: true));
//修改第3次设置version成功/失败:false
NewTableTest newTableTest4 = testMapper.selectById(id);
System.out.println("修改第3次设置version:"+newTableTest4);
//修改第3次设置version:NewTableTest(id=1, version=1, remark=修改第一次)
LambdaUpdateWrapper<NewTableTest> set = new LambdaUpdateWrapper<NewTableTest>()
.eq(NewTableTest::getVersion, newTableTest4.getVersion())
.eq(NewTableTest::getId, id)
.set(NewTableTest::getVersion,9)
.set(NewTableTest::getRemark,"测试");
int update = testMapper.update(null, set);
System.out.println("测试成功/失败:"+ (update == 0 ? false: true));
//更新实体测试成功/失败:false
NewTableTest newTableTest5 = testMapper.selectById(id);
System.out.println("测试:"+newTableTest5);
//更新实体测试:NewTableTest(id=1, version=9, remark=测试)
LambdaUpdateWrapper<NewTableTest> set2 = new LambdaUpdateWrapper<NewTableTest>()
// .eq(NewTableTest::getVersion, newTableTest5.getVersion())
.eq(NewTableTest::getId, id);
newTableTest5.setVersion(20);
newTableTest5.setRemark("更新实体测试");
int update1 = testMapper.update(newTableTest5, set2);
System.out.println("更新实体测试成功/失败:"+ (update1 == 0 ? false: true));
//测试成功/失败:true
NewTableTest newTableTest6 = testMapper.selectById(id);
System.out.println("更新实体测试:"+newTableTest6);
LambdaUpdateWrapper<NewTableTest> set22 = new LambdaUpdateWrapper<NewTableTest>()
.eq(NewTableTest::getVersion, newTableTest6.getVersion())
.eq(NewTableTest::getId, id)
.set(NewTableTest::getVersion,11)
.set(NewTableTest::getRemark,"实体不设值测试");
int update2 = testMapper.update(new NewTableTest(), set22);
//Preparing: UPDATE NEWTABLE_TEST SET version=?,remark=? WHERE (version = ? AND ID = ?)
// ==> Parameters: 11(Integer), 实体不设值测试(String), 9(Integer), 1(String)
System.out.println("实体不设值测试成功/失败:"+ (update2 == 0 ? false: true));
//更新实体测试成功/失败:true
NewTableTest newTableTest55 = testMapper.selectById(id);
System.out.println("实体不设值测试成功:"+newTableTest55);
//实体不设值测试成功:NewTableTest(id=1, version=11, remark=实体不设值测试)
//根据实体设置的值+1为set的值,实体设置的值为会被默认为当前查询出的值。
/**
* newTableTest3.setVersion(9);
* newTableTest3.setRemark("修改第3次");
* int i3 = testMapper.updateById(newTableTest3);
* Preparing: UPDATE NEWTABLE_TEST SET version=?, remark=? WHERE ID=? AND version=?
* Parameters: 10(Integer), 修改第3次(String), 1(String), 9(Integer)
*/
//实体设置的值为9,sql则使用该值当条件。当前值+1为set的值。
//所以实体设置乐观锁注解的值,查询出的该值,不能变更为其他值,否则会导致更新失败。
return R.ok();
}
}