阅读 212

MyBatis-Plus 的进阶(mybatis-plus入门)

逻辑删除的运用

1、在删除字段上增加 @TableLogic 注解

/**  * 删除标识,0未删除,1已删除  * @TableLogic 描述:表字段逻辑处理注解(逻辑删除)  */ @TableLogic private Integer deleted; 复制代码

2、配置文件中增加删除标识的值,默认是 0 表示未删除,1 表示已删除

mybatis-plus:   global-config:     db-config:       logic-delete-value: 1 # 逻辑已删除值(默认为 1)       logic-not-delete-value: 0 # 逻辑未删除值(默认为 0) 复制代码

3、测试方法

 /**    * 逻辑删除(TableLogic的使用)    *    * ==>  Preparing: UPDATE user SET deleted=1 WHERE id=? AND deleted=0    * ==> Parameters: 1094592041087729666(Long)    * <==    Updates: 1    * 影响行数:1    */ @Test public void deleteById() {     int effectNum = userMapper.deleteById(1094592041087729666L);     System.out.println("影响行数:" + effectNum); }  /**    * 根据id查询用户信息,会增加delete=0的条件    *    * ==>  Preparing: SELECT id,deleted,create_time,name,update_time,manager_id,version,email,age FROM user WHERE id=? AND deleted=0    * ==> Parameters: 1094592041087729666(Long)    * <==      Total: 0    * 用户信息:null    *    * 在deleted字段上增加注解:@TableField(select = false) 不显示deleted字段。    * ==>  Preparing: SELECT id,create_time,name,update_time,manager_id,version,email,age FROM user WHERE id=? AND deleted=0    */ @Test public void selectById() {     User user = userMapper.selectById(1094592041087729666L);     System.out.println("用户信息:" + user); } 复制代码

注意事项:自定义方法中 @TableLogic 不会起作用

自动填充的运用

1、在自动填充字段上增加 @TableField(fill = FieldFill.XXX) 注解

/**  * 创建时间  */ @TableField(fill = FieldFill.INSERT) private LocalDateTime createTime; /**  * 更新时间  */ @TableField(fill = FieldFill.UPDATE) private LocalDateTime updateTime; 复制代码

2、自定义表对象处理器 MyMetaObjectHandler,实现 MetaObjectHandler 接口

@Component public class MyMetaObjectHandler implements MetaObjectHandler {     @Override     public void insertFill(MetaObject metaObject) {         System.out.println("---insertFill---");         setInsertFieldValByName("createTime", LocalDateTime.now(), metaObject);     }     @Override     public void updateFill(MetaObject metaObject) {         System.out.println("---updateFill---");         setUpdateFieldValByName("updateTime", LocalDateTime.now(), metaObject);     } } 复制代码

3、测试方法

/**  *  新增用户,会自动填充操作时间  *  * ---insertFill---  * ==>  Preparing: INSERT INTO user ( id, create_time, name, manager_id, email, age ) VALUES ( ?, ?, ?, ?, ?, ? )  * ==> Parameters: 1260593237899411457(Long), 2020-05-13T23:28:14.124(LocalDateTime), 陈海华(String), 1088250446457389058(Long), chh@tyron.com(String), 23(Integer)  * <==    Updates: 1  * 影响行数:1  */ @Test public void insert() {     User user = new User();     user.setAge(23);     user.setName("陈海华");     user.setEmail("chh@tyron.com");     user.setManagerId(1088250446457389058L);     int effectNum = userMapper.insert(user);     System.out.println("影响行数:" + effectNum); } /**  * 更新用户信息,会自动填充更新时间  *  * ---updateFill---  * ==>  Preparing: UPDATE user SET update_time=?, age=? WHERE id=? AND deleted=0  * ==> Parameters: 2020-05-13T23:37:12.779(LocalDateTime), 24(Integer), 1260593237899411457(Long)  * <==    Updates: 1  * 影响行数:1  */ @Test public void updateById() {     User user = new User();     user.setId(1260593237899411457L);     user.setAge(24);     int effectNum = userMapper.updateById(user);     System.out.println("影响行数:" + effectNum); } 复制代码

4、根据实际情况对处理器优化

@Component public class MyMetaObjectHandler implements MetaObjectHandler {     @Override     public void insertFill(MetaObject metaObject) {         // 优化1:当有自动填充字段时再进行自动填充         boolean hasSetter = metaObject.hasSetter("createTime");         if (hasSetter) {             System.out.println("---insertFill---");             setInsertFieldValByName("createTime", LocalDateTime.now(), metaObject);         }     }     @Override     public void updateFill(MetaObject metaObject) {         // 优化2:当字段值没有设值时再自动填充         Object updateTime = getFieldValByName("updateTime", metaObject);         if (null == updateTime) {             System.out.println("---updateFill---");             setUpdateFieldValByName("updateTime", LocalDateTime.now(), metaObject);         }     } } 复制代码

乐观锁插件的运用

悲观锁(Pessimistic Locking),悲观锁是指在数据处理过程,使数据处于锁定状态,一般使用数据库的锁机制实现。适合在写多读少的并发环境中使用,虽然无法维持非常高的性能,但是在乐观锁无法提更好的性能前提下,可以做到数据的安全性。

乐观锁相对悲观锁而言,它认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则让返回错误信息,让用户决定如何去做。

利用数据版本号(version)机制是乐观锁最常用的一种实现方式。

1、配置乐观锁插件

/**  * 乐观锁插件  */ @Bean public OptimisticLockerInterceptor optimisticLockerInterceptor() { return new OptimisticLockerInterceptor(); } 复制代码

2、在版本字段上增加 @Version 注解

@Version private Integer version; 复制代码

3、测试栗子

/**   * 乐观锁-更新用户数据   *    * ==>  Preparing: UPDATE user SET update_time=?, version=?, age=? WHERE id=? AND version=? AND deleted=0   * ==> Parameters: 2020-05-17T20:42:39.527(LocalDateTime), 2(Integer), 29(Integer), 1260593237899411457(Long), 1(Integer)   * <==    Updates: 1   * 影响行数:1   */ @Test public void updateById() {     // 模拟从数据库取出版本信息     int version = 1;     User user = new User();     user.setId(1260593237899411457L);     user.setVersion(version);     user.setAge(29);     int effectNum = userMapper.updateById(user);     System.out.println("影响行数:" + effectNum); } 复制代码

执行 SQL 分析打印

1、Maven:

<dependency>   <groupId>p6spy</groupId>   <artifactId>p6spy</artifactId>   <version>最新版本</version> </dependency> 复制代码

2、application.yml 配置:

spring:   datasource:     driver-class-name: com.p6spy.engine.spy.P6SpyDriver     url: jdbc:p6spy:h2:mem:test     ... 复制代码

3、spy.properties 配置:

#3.2.1以上使用 #modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory #3.2.1以下使用或者不配置 modulelist=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory # 自定义日志打印 logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger #日志输出到控制台 #appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger #日志输出到文件中 logfile=tyron.log # 使用日志系统记录 sql #appender=com.p6spy.engine.spy.appender.Slf4JLogger # 设置 p6spy driver 代理 deregisterdrivers=true # 取消JDBC URL前缀 useprefix=true # 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset. excludecategories=info,debug,result,commit,resultset # 日期格式 dateformat=yyyy-MM-dd HH:mm:ss # 实际驱动可多个 #driverlist=org.h2.Driver # 是否开启慢SQL记录 outagedetection=true # 慢SQL记录标准 2 秒 outagedetectioninterval=2 复制代码

Sql 注入器

1.1、创建定义方法的类

@Override public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {     // 执行的SQL     String sql = "delete from " + tableInfo.getTableName();     // Mapper接口方法名     String method = "deleteAll";     SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);     return addDeleteMappedStatement(mapperClass, method, sqlSource); } 复制代码

1.2、创建注入器

@Component public class MySqlInjector extends DefaultSqlInjector {     @Override     public List<AbstractMethod> getMethodList(Class<?> mapperClass) {         List<AbstractMethod> methodList = super.getMethodList(mapperClass);         methodList.add(new DeleteAllMethod());         return methodList;     } } 复制代码

1.3、在Mapper中加入自定义方法

/**  * 删除所有数据  *  * @return 影响的行数  */ int deleteAll(); 复制代码

1.4、测试

/**  * 删除所有行数  *  * ==>  Preparing: delete from user  * ==> Parameters:  * <==    Updates: 7  * 影响的行数:7  */ @Test public void deleteAll() {     int effectNums = userMapper.deleteAll();     System.out.println("影响的行数:" + effectNums); } 复制代码

2.1、将自带批量插入注入器添加到methodList中

@Component public class MySqlInjector extends DefaultSqlInjector {    @Override     public List<AbstractMethod> getMethodList(Class<?> mapperClass) {         List<AbstractMethod> methodList = super.getMethodList(mapperClass);         methodList.add(new DeleteAllMethod());         methodList.add(new InsertBatchSomeColumn(t -> !t.isLogicDelete() && !t.getColumn().equals("age")));// 自带批量插入注入器(逻辑删除字段和年龄字段不填充)         return methodList;     } } 复制代码

2.2、在Mapper中加入自带方法

 /**   * 批量插入用户   *   * @param list 列表   * @return   */ int insertBatchSomeColumn(List<User> list); 复制代码

2.3、测试

 @Test  public void insertBatchSomeColumn() {      User user1 = new User();      user1.setName("黄呼呼");      user1.setEmail("hhh@tyron.com");      user1.setManagerId(1087982257332887553L);      user1.setAge(33);     User user2 = new User();     user2.setName("张云云");     user2.setEmail("zyy@tyron.com");     user2.setManagerId(1087982257332887553L);     user2.setAge(23);     int effectNums = userMapper.insertBatchSomeColumn(Arrays.asList(user1, user2));     System.out.println("影响的行数:" + effectNums); } 复制代码

同理的自带注入器还有:

  • LogicDeleteByIdWithFill:根据 id 逻辑删除数据,并带字段填充功能。注意入参是 entity !!! ,如果字段没有自动填充,就只是单纯的逻辑删除;

  • AlwaysUpdateSomeColumnById :根据 ID 更新固定的那几个字段(但是不包含逻辑删除)


作者:tyronchen
链接:https://juejin.cn/post/7028953797317623816


文章分类
代码人生
文章标签
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐