万隆的笔记 万隆的笔记
博文索引
笔试面试
  • 在线学站

    • 菜鸟教程 (opens new window)
    • 入门教程 (opens new window)
    • Coursera (opens new window)
  • 在线文档

    • w3school (opens new window)
    • Bootstrap (opens new window)
    • Vue (opens new window)
    • 阿里开发者藏经阁 (opens new window)
  • 在线工具

    • tool 工具集 (opens new window)
    • bejson 工具集 (opens new window)
    • 文档转换 (opens new window)
  • 更多在线资源
  • Changlog
  • Aboutme
GitHub (opens new window)
博文索引
笔试面试
  • 在线学站

    • 菜鸟教程 (opens new window)
    • 入门教程 (opens new window)
    • Coursera (opens new window)
  • 在线文档

    • w3school (opens new window)
    • Bootstrap (opens new window)
    • Vue (opens new window)
    • 阿里开发者藏经阁 (opens new window)
  • 在线工具

    • tool 工具集 (opens new window)
    • bejson 工具集 (opens new window)
    • 文档转换 (opens new window)
  • 更多在线资源
  • Changlog
  • Aboutme
GitHub (opens new window)
  • MyBatis

  • Spring-MyBatis

  • MyBatis-Plus

    • MyBaits Plus简介
    • MyBaits Plus快速入门
    • MyBaits Plus CURD
    • MyBaits Plus配置
    • Wrapper条件构造器
    • ActiveRecord
    • MyBaits Plus插件
    • MyBaits Plus拓展
      • SQL注入器
      • 自动填充
      • 添加@TableField注解
      • 逻辑删除
      • 执行SQL分析打印
      • MyBatisX快速开发插件
    • MyBaits Plus代码生成器
  • MyBatis
  • MyBatis-Plus
2022-12-31
目录

MyBaits Plus拓展

# MyBaits Plus拓展

MP提供了很多拓展功能,方便开发人员更好得开发。这里列举一些常用的功能,如SQL注入器、自动填充、SQL分析打印、逻辑删除等等,更多的可见官方文档拓展 (opens new window)一列。

# SQL注入器

我们已经知道,在MP中是通过 AbstractSqlInjector将 BaseMapper中的⽅法注⼊到了Mybatis容器,这些⽅法才可以正常执⾏。那么,如果我们需要扩充BaseMapper中的⽅法,⼜该如何实现呢?

  • 自定义自己的通用方法可以实现接口 ISqlInjector 也可以继承抽象类 AbstractSqlInjector 注入通用方法 SQL 语句,然后继承 BaseMapper 添加自定义方法,全局配置 sqlInjector 注入 MP 会自动将类所有方法注入到 MyBatis 容器中。

下⾯我们以扩展 findAll⽅法为例进⾏学习。

# 编写MyBaseMapper

public interface MyBaseMapper<T> extends BaseMapper<T> {

    List<T> findAll();

}

其他的Mapper都可以继承该Mapper,这样实现了统⼀的扩展。如:

public interface UserMapper extends MyBaseMapper<User> {

}

# 编写MySqlInjector

如果直接继承 AbstractSqlInjector的话,原有的BaseMapper中的⽅法将失效,所以我们选择继承 DefaultSqlInjector进⾏扩展。

public class MySqlInjector extends DefaultSqlInjector {

    @Override
    public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
        List<AbstractMethod> methodList = super.getMethodList(mapperClass);
        // 扩充⾃定义的⽅法
        methodList.add(new FindAll());
        return methodList;
    }

}

# 编写FindAll

public class FindAll extends AbstractMethod {
    @Override
    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
        String sqlMethod = "findAll";
        String sql = "select * from " + tableInfo.getTableName();
        SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
        return this.addSelectMappedStatementForTable(mapperClass, sqlMethod, sqlSource, tableInfo);
    }
}

# 注册到Spring容器

/**
* ⾃定义SQL注⼊器
*/
@Bean
public MySqlInjector mySqlInjector(){
 return new MySqlInjector();
}

# 测试用例

@RunWith(SpringRunner.class)
@SpringBootTest
public class MPExtendTest {

    @Autowired
    private UserMapper userMapper;

    @Test
    public void testTenant() {
        List<User> allUser = userMapper.findAll();
        System.out.println(allUser);
        // [User(id=1, name=Jone, age=18, email=test1@baomidou.com, tenantId=null, version=null), User(id=3, name=Tom, age=28, email=test3@baomidou.com, tenantId=null, version=null), User(id=4, name=Sandy, age=21, email=test4@baomidou.com, tenantId=null, version=null), User(id=5, name=Billie, age=24, email=test5@baomidou.com, tenantId=null, version=null)]
    }
}

⾄此,我们实现了全局扩展SQL注⼊器。

# 自动填充

有些时候我们可能会有这样的需求,插⼊或者更新数据时,希望有些字段可以⾃动填充数据,⽐如create_time、update_time、version等。在MP中提供了这样的功能,可以实现⾃动填充。

# 实现MetaObjectHandler接口

 @Slf4j
 @Component
 public class MyMetaObjectHandler implements MetaObjectHandler {
 
     @Override
     public void insertFill(MetaObject metaObject) {
         log.info("start insert fill ....");
         this.strictInsertFill(metaObject, "createTime", LocalDateTime::now, LocalDateTime.class);
     }
 
     @Override
     public void updateFill(MetaObject metaObject) {
         log.info("start update fill ....");
         this.strictInsertFill(metaObject, "updateTime", LocalDateTime::now, LocalDateTime.class);
     }
 
 }

# 添加@TableField注解

@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;

FieldFill说明:

public enum FieldFill {
    /**
     * 默认不处理
     */
    DEFAULT,
    /**
     * 插入填充字段
     */
    INSERT,
    /**
     * 更新填充字段
     */
    UPDATE,
    /**
     * 插入和更新填充字段
     */
    INSERT_UPDATE
}

往user表中补充creat_time、update_time,测试用例:

@Test
public void testAutoFill() {
    User user = new User();
    user.setName("autofill");
    user.setAge(18);
    user.setEmail("autofill@baomidou.com");
    userMapper.insert(user);
    System.out.println(user);
    // User(id=18, name=autofill, age=18, email=autofill@baomidou.com, tenantId=null, version=null, createTime=2022-12-31T23:37:03.520, updateTime=null)
    user.setAge(19);
    userMapper.updateById(user);
    // User(id=18, name=autofill, age=19, email=autofill@baomidou.com, tenantId=null, version=null, createTime=2022-12-31T23:37:03.520, updateTime=2023-05-14T23:37:03.837)
    System.out.println(user);
}

注意事项:

  • 填充原理是直接给 entity的属性设置值!!!
  • 注解则是指定该属性在对应情况下必有值,如果无值则入库会是 null
  • MetaObjectHandler提供的默认方法的策略均为:如果属性有值则不覆盖,如果填充值为 null则不填充
  • 字段必须声明 TableField注解,属性 fill选择对应策略,该声明告知 Mybatis-Plus需要预留注入 SQL字段
  • 填充处理器 MyMetaObjectHandler在 Spring Boot 中需要声明 @Component或 @Bean注入
  • 要想根据注解 FieldFill.xxx和 字段名以及 字段类型来区分必须使用父类的 strictInsertFill或者 strictUpdateFill方法
  • 不需要根据任何来区分可以使用父类的 fillStrategy方法
  • update(T t,Wrapper updateWrapper)时t不能为空,否则自动填充失效

# 逻辑删除

开发系统时,有时候在实现功能时,删除操作需要实现逻辑删除,所谓逻辑删除就是将数据标记为删除,⽽并⾮真正的物理删除(⾮DELETE操作),查询时需要携带状态条件,确保被标记的数据不被查询到。这样做的⽬的就是避免数据被真正的删除。

MP就提供了这样的功能,⽅便我们使⽤,接下来我们⼀起学习下。

# 修改表结构

为user表增加deleted字段,⽤于表示数据是否被删除,1代表删除,0代表未删除。

ALTER TABLE `user` ADD COLUMN `deleted` int(1) NULL DEFAULT 0 COMMENT '1代表删除,0代表未删除' AFTER `version`;

同时,也修改User实体,增加deleted属性并且添加 @TableLogic注解:

@TableLogic
private Integer deleted;

# 配置application.yml

mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: deleted # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

# 测试用例

@Test
public void testLogicDeleted() {
    userMapper.deleteById(1L);
    // UPDATE user SET deleted=1 WHERE id=1 AND deleted=0
    User user = userMapper.selectById(1L);
    // SELECT id,name,age,email,tenant_id,version,create_time,update_time,deleted FROM user WHERE id=1 AND deleted=0
    Assert.assertNull(user);
}

# 常见问题

  1. 如何 insert ?
    • 字段在数据库定义默认值(推荐)
    • insert 前自己 set 值
    • 使用 自动填充功能
  2. 删除接口自动填充功能失效
    • 使用 deleteById 方法(推荐)
    • 使用 update 方法并: UpdateWrapper.set(column, value)(推荐)
    • 使用 update 方法并: UpdateWrapper.setSql("column=value")
    • 使用 Sql 注入器 注入 com.baomidou.mybatisplus.extension.injector.methods.LogicDeleteByIdWithFill 并使用(3.5.0版本已废弃,推荐使用deleteById)

# 执行SQL分析打印

该功能依赖 p6spy 组件,完美的输出打印 SQL 及执行时长。需要 3.1.0 以上版本。

  • 该插件有性能损耗,不建议生产环境使用。

# 引入依赖

Maven:

<dependency>
  <groupId>p6spy</groupId>
  <artifactId>p6spy</artifactId>
  <version>最新版本</version>
</dependency>

Gradle:

compile group: 'p6spy', name: 'p6spy', version: '最新版本'

application.yml:

spring:
  datasource:
    driver-class-name: com.p6spy.engine.spy.P6SpyDriver
    url: jdbc:p6spy:mysql://127.0.0.1:3306/mybatis_plus?characterEncoding=utf-8

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
# 使用日志系统记录 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

说明:

  • driver-class-name 为 p6spy 提供的驱动类
  • url 前缀为 jdbc:p6spy 跟着冒号为对应数据库连接地址
  • 打印出 sql 为 null,在 excludecategories 增加 commit
  • 批量操作不打印 sql,去除 excludecategories 中的 batch
  • 批量操作打印重复的问题请使用 MybatisPlusLogFactory (3.2.1 新增)

执行SQL后将会打印如下信息:

2022-12-31 22:06:04.553  INFO 32565 --- [           main] o.e.h.m.m.MPMapperCURDTest               : Started MPMapperCURDTest in 0.804 seconds (JVM running for 1.345)
 Consume Time:10 ms 2022-12-31 22:06:04
 Execute SQL:SELECT id,name,age,email,tenant_id,version,create_time,update_time,deleted FROM user WHERE deleted=0 AND (age > 20)

# MyBatisX快速开发插件

MybatisX 是一款基于 IDEA 的快速开发插件,为效率而生。教程见官网 (opens new window)。

上次更新: 5/30/2023, 11:23:39 PM
MyBaits Plus代码生成器

MyBaits Plus代码生成器→

最近更新
01
2025
01-15
02
Elasticsearch面试题
07-17
03
Elasticsearch进阶
07-16
更多文章>
Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式