前言
MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
一、MyBatis-Plus配置GlobalConfig
MyBatis-Plus配置全局配置都是在GlobalConfig中
public class GlobalConfig implements Serializable {
private boolean banner = true;//是否开启 LOGO
private boolean enableSqlRunner = false;//是否初始化 SqlRunner
private DbConfig dbConfig;//数据库相关配置
private ISqlInjector sqlInjector = new DefaultSqlInjector();// SQL注入器
private Class<?> superMapperClass = Mapper.class;// Mapper父类
private Set<String> mapperRegistryCache = new ConcurrentSkipListSet<>();//缓存已注入CRUD的Mapper信息
private MetaObjectHandler metaObjectHandler;//元对象字段填充控制器
private IdentifierGenerator identifierGenerator;//主键生成器
//这是数据库相关的配置,下面重点说
@Data
public static class DbConfig {
//忽略代码.....
}
}
SQL注入器是为BaseMapper全局新的方法
1.1 元对象字段填充控制器
有些时候我们可能会有这样的需求,插入或者更新数据时,希望有些字段可以自动填充数据,比如insetTime、updateTime等。在MP中提供了这样的功能,可以实现自动填充。
实现步骤如下:实现元对象处理器接口:com.baomidou.mybatisplus.core.handlers.MetaObjectHandler
MetaObjectHandler提供的默认方法的策略均为:如果属性有值则不覆盖,如果填充值为null则不填充
public class MyMetaObjectHandler implements MetaObjectHandler {
//新增数据时执行
@Override
public void insertFill(MetaObject metaObject) {
//创建时间、更新时间
this.strictInsertFill(metaObject, "insertTime", Date.class, new Date());
this.strictInsertFill(metaObject, "updateTime", Date.class, new Date());
}
//更新数据时执行
@Override
public void updateFill(MetaObject metaObject) {
this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
}
}
实现好我们自己的MetaObjectHandler后,我们还要通过@TableField指定字段的填充策略,如下
@TableName("person")
public class Person {
//忽略代码。。。
@TableField(value ="insert_time", fill = FieldFill.INSERT)
private Date insertTime;
@TableField(value ="update_time",fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
FieldFill是一个枚举
public enum FieldFill {
DEFAULT,//默认不处理
INSERT,//插入填充字段
UPDATE,//更新填充字段
INSERT_UPDATE//插入和更新填充字段
}
对了,别忘了MetaObjectHandler在Spring中的注册
这是在SpringMVC中的注册
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
MybatisSqlSessionFactoryBean factoryBean = new MybatisSqlSessionFactoryBean();
//忽略代码....
factoryBean.setGlobalConfig(globalConfig());
return factoryBean.getObject();
}
@Bean
public GlobalConfig globalConfig() {
GlobalConfig globalConfig = new GlobalConfig();
globalConfig.setMetaObjectHandler(new MyMetaObjectHandler());
return globalConfig;
}
而在SpringBoot就简单多了,我只想要需要声明@Component或@Bean注入就行了
常规MyBatis-Plus全局配置设置如下(这里写成yml方式)
mybatis-plus:
global-config:
banner: false
二、数据库相关配置
public class GlobalConfig implements Serializable {
//忽略代码....
private DbConfig dbConfig;//数据库相关配置
@Data
public static class DbConfig {
private IdType idType = IdType.ASSIGN_ID;//主键类型
private String tablePrefix;//表名前缀
private String schema;
private String columnFormat;
//entity 的字段(property)的 format,只有在 column as property 这种情况下生效,对主键无效
private String propertyFormat;//
private boolean replacePlaceholder;//实验性功能,占位符替换
private String escapeSymbol;
private boolean tableUnderline = true;//表名是否使用驼峰转下划线命名,只对表名生效
private boolean capitalMode = false;//大写命名,对表名和字段名均生效
private IKeyGenerator keyGenerator;//表主键生成器
private String logicDeleteField;//逻辑删除全局属性名
private String logicDeleteValue = "1";//逻辑删除全局值(默认 1、表示已删除)
private String logicNotDeleteValue = "0";//逻辑未删除全局值(默认 0、表示未删除)
private FieldStrategy insertStrategy = FieldStrategy.NOT_NULL;//字段验证策略之insert
private FieldStrategy updateStrategy = FieldStrategy.NOT_NULL;//字段验证策略之 update
private FieldStrategy selectStrategy = FieldStrategy.NOT_NULL;// 字段验证策略之 select
}
}
2.1 逻辑删除
private String logicDeleteField;//逻辑删除全局属性名
private String logicDeleteValue = "1";//逻辑删除全局值(默认 1、表示已删除)
private String logicNotDeleteValue = "0";//逻辑未删除全局值(默认 0、表示未删除)
springMVC配置如下
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
MybatisSqlSessionFactoryBean factoryBean = new MybatisSqlSessionFactoryBean();
//忽略代码....
factoryBean.setGlobalConfig(globalConfig());
return factoryBean.getObject();
}
@Bean
public GlobalConfig globalConfig() {
GlobalConfig globalConfig = new GlobalConfig();
GlobalConfig.DbConfig dbConfig = new GlobalConfig.DbConfig();
dbConfig.setLogicDeleteField("state");
dbConfig.setLogicDeleteValue("1");
dbConfig.setLogicNotDeleteValue("0");
globalConfig.setDbConfig(dbConfig);
return globalConfig;
}
2.2 字段验证策略之insert
private FieldStrategy insertStrategy = FieldStrategy.NOT_NULL;//字段验证策略之insert
Person person = new Person();
person.setName("clyu112");
personDao.insert(person);
不同的 验证策略之insert生成的SQL是不一样的
FieldStrategy.IGNORED INSERT INTO person ( id, name, age, name_en, state ) VALUES ( null, 'clyu112', null, null, null );
FieldStrategy.NOT_NULL INSERT INTO person ( id, name ) VALUES ( null, 'clyu112' );
FieldStrategy.NOT_EMPTY INSERT INTO person ( id, name ) VALUES ( null, 'clyu112' );
FieldStrategy.DEFAULT INSERT INTO person ( id, name ) VALUES ( null, 'clyu112' );
FieldStrategy.NEVER INSERT INTO person ( id ) VALUES ( null );
NOT_EMPTY和NOT_NULL区别在于:如果设置NOT_EMPTY的话 ,值为null,“”,不会插入数据库,而NOT_NULL,值为null,不会插入数据库
2.23 字段验证策略之update
private FieldStrategy updateStrategy = FieldStrategy.NOT_NULL;//字段验证策略之 update
Person person = new Person();
person.setName("clyu112");
person.setId("3");
personDao.updateById(person);
不同的 验证策略之update生成的SQL是不一样的
FieldStrategy.IGNORED. UPDATE person SET name='clyu112', age=null, name_en=null, state=null WHERE id='3';
FieldStrategy.NOT_NULL UPDATE person SET name='clyu112' WHERE id='3';
FieldStrategy.NOT_EMPTY UPDATE person SET name='clyu112' WHERE id='3';
FieldStrategy.DEFAULT. UPDATE person SET name='clyu112' WHERE id='3';
FieldStrategy.NEVER UPDATE person WHERE id='3';
springMVC配置如下
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
MybatisSqlSessionFactoryBean factoryBean = new MybatisSqlSessionFactoryBean();
//忽略代码....
factoryBean.setGlobalConfig(globalConfig());
return factoryBean.getObject();
}
@Bean
public GlobalConfig globalConfig() {
GlobalConfig globalConfig = new GlobalConfig();
GlobalConfig.DbConfig dbConfig = new GlobalConfig.DbConfig();
dbConfig.setUpdateStrategy(FieldStrategy.NEVER);
dbConfig.setInsertStrategy(FieldStrategy.NEVER);
globalConfig.setDbConfig(dbConfig);
return globalConfig;
}
2.24 主键类型
private IKeyGenerator keyGenerator;//表主键生成器
private IdType idType = IdType.ASSIGN_ID;//主键类型
IdType是一个枚举
public enum IdType {
AUTO(0),//数据库ID自增<p>该类型请确保数据库设置了 ID自增 否则无效</p>
NONE(1),//该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
INPUT(2), //用户输入ID<p>该类型可以通过自己注册自动填充插件进行填充</p>
//自动分配ID,
//默认实现类 {@link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}(雪花算法)
ASSIGN_ID(3),
//自动分配UUID (主键类型为 string)
//默认实现类 {@link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}(UUID.replace("-",""))
ASSIGN_UUID(4);
}
当我们想指定我们想要的主键生成器,那么主键生成策略必须使用 INPUT,MyBatis-Plus内置主键生成器如下
DB2KeyGenerator
H2KeyGenerator
KingbaseKeyGenerator
OracleKeyGenerator
PostgreKeyGenerator
如果内置支持不满足你的需求,可实现 IKeyGenerator 接口来进行扩展.
常规MyBatis-Plus数据库相关配置设置如下(这里写成yml方式)
mybatis-plus:
global-config:
db-config:
insert-strategy: not_null
update-strategy: not_null
select-strategy: not_null
# 主键类型:
# AUTO(0),数据库ID自增
# NONE(1),未设置主键类型
# INPUT(2),用户输入ID
# ASSIGN_ID(3),全局唯一ID (数字类型唯一ID)
# ASSIGN_UUID(4),全局唯一ID UUID
id-type: INPUT
# 是否开启大写命名,默认不开启
capital-mode: false
logic-delete-field: deleteFlag
logic-delete-value: 1
logic-not-delete-value: 0
三、通用枚举
这些配置都在MybatisSqlSessionFactoryBean的属性中配置
Mybatis中有2种枚举类型处理器是他们分别是EnumTypeHandler(用来存储枚举的名称)和EnumOrdinalTypeHandler(用来存储枚举的序数值),其默认枚举类型处理器是EnumTypeHandler,如果我们想要存储枚举别的属性,除了自定义TypeHandler,我们也可以使用MyBatis-Plus通用枚举功能
通用枚举有2中实现方式,一使用@EnumValue注解,二实现IEnum接口
方法一:@EnumValue注解
枚举数据库存储值是@EnumValue标注方法的返回值
public enum GradeEnum {
PRIMARY(1, "小学"), SECONDORY(2, "中学"), HIGH(3, "高中");
GradeEnum(int code, String descp) {
this.code = code;
this.descp = descp;
}
@EnumValue//标记数据库存的值是code
private final int code;
//。。。
}
方式二: 枚举属性,实现 IEnum 接口如下:
枚举数据库存储值是getValue()方法的返回值
public enum AgeEnum implements IEnum<Integer> {
ONE(1, "一岁"),
TWO(2, "二岁"),
THREE(3, "三岁");
private int value;
private String desc;
@Override
public Integer getValue() {
return this.value;
}
}
测试,实体属性使用枚举类型
public class User {
private String name;
private AgeEnum age;
private GradeEnum grade;
}
SpringMVC配置扫描通用枚举配置
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
MybatisSqlSessionFactoryBean factoryBean = new MybatisSqlSessionFactoryBean();
//忽略代码.....
factoryBean.setTypeEnumsPackage("learnning.demo.enums");//扫描这个包下的所有枚举
return factoryBean.getObject();
}
测试insert成功,但是在测试查询时,报java.sql.SQLFeatureNotSupportedException错误(目前不知道原因)
SpringBoot配置扫描通用枚举配置
mybatis-plus:
typeEnumsPackage: learnning.demo.enums
测试insert成功,查询成功
四、分页
MyBatis-Plus中反应插件是PaginationInnerInterceptor,其属性如下
public class PaginationInnerInterceptor implements InnerInterceptor {
//溢出总页数后是否进行处理 true:回到首页,false:不处理 默认false
protected boolean overflow;
//单页分页条数限制
protected Long maxLimit;
//数据库类型,建议单一数据库类型的均设置 dbType,提高速率
private DbType dbType;
//方言实现类
private IDialect dialect;
//生成 countSql 优化掉 join。现在只支持 left join
protected boolean optimizeJoin = true;
//忽略代码 。。。。。
SpringMVC中配置分页
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
MybatisSqlSessionFactoryBean factoryBean = new MybatisSqlSessionFactoryBean();
//忽略代码..
factoryBean.setPlugins(mybatisPlusInterceptor());
return factoryBean.getObject();
}
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(paginationInnerInterceptor());
return interceptor;
}
@Bean
public PaginationInnerInterceptor paginationInnerInterceptor(){
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
paginationInnerInterceptor.setMaxLimit(1000L);//设置单页分页条数限制1000
return paginationInnerInterceptor;
}
SpringBoot中配置分页
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(paginationInnerInterceptor());
return interceptor;
}
@Bean
public PaginationInnerInterceptor paginationInnerInterceptor(){
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
paginationInnerInterceptor.setMaxLimit(1000L);//设置单页分页条数限制1000
return paginationInnerInterceptor;
}
配置好后,其dao层分页接口可以像下面这样写
@Mapper
public interface PersonDao extends BaseMapper<Person> {
//注意第二个person必须要用@Param注明
IPage<Person> queryAll(Page page, @Param("person") Person person);
}
五、防全表更新与删除插件
这里以SpringBoot环境为例,配置如下
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(blockAttackInnerInterceptor());
return interceptor;
}
@Bean
public BlockAttackInnerInterceptor blockAttackInnerInterceptor(){
BlockAttackInnerInterceptor blockAttackInnerInterceptor = new BlockAttackInnerInterceptor();
return blockAttackInnerInterceptor;
}