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);
}
# 常见问题
- 如何 insert ?
- 字段在数据库定义默认值(推荐)
- insert 前自己 set 值
- 使用 自动填充功能
- 删除接口自动填充功能失效
- 使用
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)。