mybatis-plus之逻辑删除&自动填充&乐观锁
1.背景
mybatis-plus除了常规的一些CRUD还有其他的的功能如下
2.逻辑删除
2.1.实现配置
步骤一、数据库准备一个逻辑删除字段,一般是deleted
步骤二、配置文件中添加入下配置
步骤三、java实体上加标签如下:
2.2.实际案例演示
package com.ldp.demo01; import com.ldp.entity.SysUser; import com.ldp.mapper.SysUserMapper; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; /** * @author 姿势帝-博客园 * @address https://www.cnblogs.com/newAndHui/ * @WeChat 851298348 * @create 12/14 7:13 * @description <p> * 逻辑删除测试 * </p> */ @RunWith(SpringRunner.class) @SpringBootTest public class Test11LogicDeleted { @Autowired private SysUserMapper sysUserMapper; /** * 逻辑删除测试 * <p> * ==> Preparing: UPDATE sys_user SET deleted=1 WHERE id=? AND deleted=0 * ==> Parameters: 26(Integer) * <== Updates: 1 * <p> * 注意观察:虽然我执行的是删除,但是因为配置了逻辑删除,使用最后执行的本质sql是更新, * 而且在更新的sql语句中还加入了deleted=0这个条件 * 那么试想一想,如果是查询、修改会加入deleted=0这个条件么? */ @Test public void test01() { int row = sysUserMapper.deleteById(25); System.out.println("受影响行数:" + row); } /** * 测试逻辑删除下的查询 * <p> * ==> Preparing: SELECT id,version,age,gender,name,parent_id,position,account,we_chat,password,status,type,create_time,update_time,deleted * FROM sys_user WHERE id=? AND deleted=0 * ==> Parameters: 25(Integer) * <p> * 注意逻辑删除下的查询是加了 AND deleted=0 作为查条件的 */ @Test public void test02() { SysUser sysUser = sysUserMapper.selectById(25); System.out.println("sysUser=" + sysUser); } /** * 逻辑删除下的更新 * <p> * ==> Preparing: UPDATE sys_user SET name=? WHERE id=? AND deleted=0 * ==> Parameters: 逻辑删除测试(String), 25(Integer) * <p> * 注意从sql语句上看也是添加了deleted=0的 */ @Test public void test03() { int row = sysUserMapper.updateById(new SysUser().setId(25).setName("逻辑删除测试")); System.out.println("受影响行数=" + row); } /** * 逻辑删除下的新增 * ==> Preparing: INSERT INTO sys_user ( age, name ) VALUES ( ?, ? ) * ==> Parameters: 18(Integer), 新增测试(String) * <== Updates: 1 * 注意从sql语句来看,在添加的时候并没有帮我们自动添加deleted=0字段的值, * 所有在实际生产中最佳的作法是在数据库设置默认值为0 */ @Test public void test04() { int row = sysUserMapper.insert(new SysUser().setName("新增测试").setAge(18)); System.out.println("受影响行数=" + row); } }
3.自动填充
第一步:注解填充字段 @TableField(.. fill = FieldFill.INSERT)
生成器策略部分也可以配置!
/** * 表示创建时自动填充 */ @TableField(value = "create_time",fill = FieldFill.INSERT) private Date createTime; /** * 表示更新时自动填充 */ @TableField(fill = FieldFill.UPDATE) private Date updateTime;
第二步:自定义实现类 MyMetaObjectHandler
package com.ldp.config; import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.reflection.MetaObject; import org.springframework.stereotype.Component; import java.util.Date; /** * @author 姿势帝-博客园 * @address https://www.cnblogs.com/newAndHui/ * @WeChat 851298348 * @create 12/14 8:03 * @description */ @Slf4j @Component public class MyMetaObjectHandler implements MetaObjectHandler { @Override public void insertFill(MetaObject metaObject) { log.info("start insert fill ...."); this.strictInsertFill(metaObject, "createTime", () -> new Date(), Date.class); // 起始版本 3.3.3(推荐) } @Override public void updateFill(MetaObject metaObject) { log.info("start update fill ...."); this.strictUpdateFill(metaObject, "updateTime", () -> new Date(), Date.class); // 起始版本 3.3.3(推荐) } }
第三步:测试
package com.ldp.demo01; import com.ldp.entity.SysUser; import com.ldp.mapper.SysUserMapper; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; /** * @author 姿势帝-博客园 * @address https://www.cnblogs.com/newAndHui/ * @WeChat 851298348 * @create 12/14 8:10 * @description <p> * 自动填充 * </p> */ @RunWith(SpringRunner.class) @SpringBootTest public class Test12FieldFill { @Autowired private SysUserMapper sysUserMapper; /** * 新增时自动填充 * <p> * ==> Preparing: INSERT INTO sys_user ( age, name, create_time ) VALUES ( ?, ?, ? ) * ==> Parameters: 18(Integer), 自动填充(String), 2020-12-14 19:55:36.065(Timestamp) * <== Updates: 1 */ @Test public void test01() { int row = sysUserMapper.insert(new SysUser().setName("自动填充").setAge(18)); System.out.println("受影响行数=" + row); } /** * 更新时自动填充 * <p> * ==> Preparing: UPDATE sys_user SET name=?, update_time=? WHERE id=? AND deleted=0 * ==> Parameters: 更新自动填充(String), 2020-12-14 19:56:16.539(Timestamp), 25(Integer) * <== Updates: 1 */ @Test public void test02() { int row = sysUserMapper.updateById(new SysUser().setId(25).setName("更新自动填充")); System.out.println("受影响行数=" + row); } }
4.乐观锁
实现原理:
取出记录时,获取当前version 更新时,带上这个version 执行更新时, set version = newVersion where version = oldVersion 如果version不对,就更新失败
具体实现
第一步:数据库和java实体添加字段version,并在实体上添加注解@Version
/** * 乐观锁 */ @Version private Integer version;
第二步:注册乐观锁插件
package com.ldp.config; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor; import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @author 姿势帝-博客园 * @address https://www.cnblogs.com/newAndHui/ * @WeChat 851298348 * @create 12/06 4:45 * @description */ @Configuration public class MybatisPlusConfig { /** * 乐观锁配置 * * @return */ @Bean public MybatisPlusInterceptor optimisticLockerInnerInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return interceptor; } @Bean public PaginationInterceptor paginationInterceptor() { PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false // paginationInterceptor.setOverflow(false); // 设置最大单页限制数量,默认 500 条,-1 不受限制 // paginationInterceptor.setLimit(500); // 开启 count 的 join 优化,只针对部分 left join paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true)); return paginationInterceptor; } }
第三步:测试
package com.ldp.demo01; import com.ldp.entity.SysUser; import com.ldp.mapper.SysUserMapper; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; /** * @author 姿势帝-博客园 * @address https://www.cnblogs.com/newAndHui/ * @WeChat 851298348 * @create 12/14 9:40 * @description */ @RunWith(SpringRunner.class) @SpringBootTest public class Test13Version { @Autowired private SysUserMapper sysUserMapper; /** * 乐观锁测试 * ==> Preparing: UPDATE sys_user SET version=?, name=?, update_time=? WHERE id=? AND version=? AND deleted=0 * ==> Parameters: 8(Integer), 乐观锁测试(String), 2020-12-14 22:04:15.04(Timestamp), 12(Integer), 7(Integer) * <== Updates: 1 * 注意观察sql,查询出来的version=7,在更新的时候将session版本设置为8 */ @Test public void test01() { SysUser sysUser = sysUserMapper.selectById(12); int row = sysUserMapper.updateById( new SysUser() .setId(sysUser.getId()) .setName("乐观锁测试") .setVersion(sysUser.getVersion()) ); System.out.println("受影响行数=" + row); } }