文章目录
一、概述
虽然mybatis可以直接在xml中通过SQL语句操作数据库,很是灵活。但正因其操作都要通过SQL语句进行,就必须写大量的xml文件,很是麻烦。mybatis-plus就很好的解决了这个问题。
官方的定义:Mybatis-Plus
(简称MP
)是一个 Mybatis 的增强工具,在 Mybatis 的基础上只做增强不做改变,为简化开发、提高效率而生。这是官方给的定义,关于mybatis-plus的更多介绍及特性,可以参考mybatis-plus官网。那么它是怎么增强的呢?其实就是它已经封装好了一些crud方法,我们不需要再写xml了,直接调用这些方法就行,就类似于JPA。
-
文档地址:https://mp.baomidou.com/guide/
官方文档已经写的很详细了,本文主要是对官方文档的一个自我学习的总结
二、准备工作
这里使用的是Spring Boot 和 Mysql
1. 添加依赖
在Spring Boot 工程中添加 Mybatis-Plus 依赖(不需要添加Mybatis的依赖了)和Mysql驱动包依赖:
Maven仓库中的MybatisPlus依赖:https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--lombok简化代码-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
2. 配置数据库
在application.yaml文件中配置数据库
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=CTT
username: root
password: 123
3. 添加@MapperScan注解
在 Spring Boot 启动类中添加 @MapperScan 注解,扫描 Mapper 文件夹:
@SpringBootApplication
@MapperScan("com.test.mapper")
public class Application {
public static void main(String[] args) {
SpringApplication.run(QuickStartApplication.class, args);
}
}
4. 编写实体类
实体类中会需要用到一些注解,之后再详细的说。
@Data
@TableName("t_user")
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
5. 编写Mapper接口
编写 Mapper 接口时,继承 BaseMapper<T>
父接口,泛型 T
是这个 Mapper 对应的实体类, BaseMapper<T>
父接口中已经将通用的 CRUD 封装好了,直接使用即可,后面也会说。
public interface UserMapper extends BaseMapper<User> {
}
至此,一个简单的 Mybatis-Plus
已经集成完毕
三、实体类中的注解
1. @TableName(表名注解)
属性 | 类型 | 必须指定 | 默认值 | 描述 |
---|---|---|---|---|
value | String | 否 | “” | 指定表名(当表名与实体类名不一致(不满足驼峰和下划线的映射关系)时,用该属性指定实体类对应的表名) |
2. @TableId(主键注解)
属性 | 类型 | 必须指定 | 默认值 | 描述 |
---|---|---|---|---|
value | String | 否 | “” | 主键字段名 |
type | Enum | 否 | IdType.NONE | 主键类型 |
IdType(主键类型)
值 | 描述 |
---|---|
AUTO | 数据库ID自增 |
NONE | 该类型为未设置主键类型(将跟随全局) |
INPUT | 插入前手动输入 |
ID_WORKER | 全局唯一ID (idWorker、雪花算法)(只有当插入对象ID 为空,才自动填充)(默认) |
UUID | 全局唯一ID (UUID)(只有当插入对象ID 为空,才自动填充) |
ID_WORKER_STR | 字符串全局唯一ID (idWorker 的字符串表示)(只有当插入对象ID 为空,才自动填充) |
3. @TableField(非主键字段注解)
属性 | 类型 | 必须指定 | 默认值 | 描述 |
---|---|---|---|---|
value | String | 否 | “” | 指定数据库字段名(与@TableName注解中的value属性类似,只不过这个是指定非主键字段名) |
exist | boolean | 否 | true | 是否为数据库表字段 |
fill | Enum | 否 | FieldFill.DEFAULT | 字段自动填充策略(可以设置更新或者插入时自动填充) |
四、BaseMapper<T>中的方法
1. 插入
// 插入一条记录
int insert(T entity);
-
参数说明:
类型 参数名 描述 T entity 实体对象
2. 删除
// 根据 wrapper 条件,删除记录
int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);
// 根据ID 的集合批量删除
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
// 根据 ID 删除
int deleteById(Serializable id);
// 根据 columnMap 条件,删除记录
int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
-
参数说明:
类型 参数名 描述 Wrapper wrapper 实体对象封装操作类(可以为 null) Collection<? extends Serializable> idList 主键ID列表(不能为 null 以及 empty) Serializable id 主键ID Map<String, Object> columnMap 表字段 map 对象,键是表的列名
3. 更新
// 根据 updateWrapper 条件,更新记录
int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);
// 根据 ID 修改,如果entity中的某个字段为空,则这个字段就不会出现在sql语句中
int updateById(@Param(Constants.ENTITY) T entity);
-
参数说明:
类型 参数名 描述 T entity 实体对象 (set 条件值,可为 null) Wrapper updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)
4. 查询
-
只查询一个:
// 根据 ID 查询 T selectById(Serializable id); // 根据 entity 条件,查询一条记录 T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
-
查询多个:
// 查询(根据ID 批量查询) List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList); // 根据 entity 条件查询,返回实体类 List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper); // 查询(根据某些列的值查询),注意:map中的键是表的列名 List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap); // 根据 Wrapper 条件查询,返回回来的是 map 而不是实体类 List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper); // 根据 Wrapper 条件,查询全部记录。注意: 只返回第一个字段的值 List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
-
分页查询(详见“九、分页查询”):
// 根据 queryWrapper 条件进行分页查询,要配置分页插件。使用方法详见 "九、分页查询" // 第一个形参page:可以使用Page对象,new Page(current, size),current表示当前页,size表示每页显示条数 IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper); // 同上一个方法,返回值是map IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper); // 根据 Wrapper 条件,查询总记录数 Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
-
参数说明:
类型 参数名 描述 Serializable id 主键ID Wrapper queryWrapper 实体对象封装操作类(可以为 null) Collection<? extends Serializable> idList 主键ID列表(不能为 null 以及 empty) Map<String, Object> columnMap 表字段 map 对象 IPage page 分页查询条件(可以为 RowBounds.DEFAULT,也可以使用Page对象)
五、条件构造器
这部分官方文档已经写的很清楚了,也比较简单,我就说一下常用的好了。
官方文档:https://mp.baomidou.com/guide/wrapper.html#abstractwrapper
-
常用的
AbstractWrapper
父类方法,该父类用于生成 sql 的 where 条件:注意:下面的每个方法,基本上都有一个重载方法,这个重载方法都是在形参的一个参数位置,增加了:
boolean condition
形参(其余参数后移一位),用来表示该条件是否加入最后生成的sql中eq(R column, Object val)//等于, 例: eq("name", "老王")--->name = '老王' ne(R column, Object val)//不等于 gt(R column, Object val)//大于 ge(R column, Object val)//>= lt(R column, Object val)//< le(R column, Object val)//<= between(R column, Object val1, Object val2)//BETWEEN 值1 AND 值2 notBetween(R column, Object val1, Object val2)//NOT BETWEEN 值1 AND 值2 like(R column, Object val)//LIKE '%值%' notLike(R column, Object val)//NOT LIKE '%值%' likeLeft(R column, Object val)//LIKE '%值' likeRight(R column, Object val)//LIKE '值%' isNull(R column)//字段 IS NULL isNotNull(R column)//字段 IS NOT NULL in(R column, Collection<?> value)//字段 IN (value.get(0), value.get(1), ...) in(R column, Object... values)//字段 IN (v0, v1, ...) inSql(R column, String inValue)//字段 IN ( sql语句 ) notIn(R column, Collection<?> value)//字段 NOT IN (value.get(0), value.get(1), ...) notIn(R column, Object... values)//字段 NOT IN (v0, v1, ...) notInSql(R column, String inValue)//字段 NOT IN ( sql语句 ) groupBy(R... columns)//分组:GROUP BY 字段, ... having(String sqlHaving, Object... params)//HAVING ( sql语句 ); 例: having("sum(age) > {0}", 11)--->having sum(age) > 11 orderBy(boolean condition, boolean isAsc, R... columns)//排序:ORDER BY 字段, ... orderByAsc(R... columns)//排序:ORDER BY 字段, ... ASC orderByDesc(R... columns)//排序:ORDER BY 字段, ... DESC or()//拼接 OR; 例: eq("id",1).or().eq("name","老王")--->id = 1 or name = '老王' or(Consumer<Param> consumer)//OR 嵌套; 例: or(i -> i.eq("name", "李白").ne("status", "活着"))--->or (name = '李白' and status <> '活着') and(Consumer<Param> consumer)//AND 嵌套; 例: and(i -> i.eq("name", "李白").ne("status", "活着"))--->and (name = '李白' and status <> '活着') nested(Consumer<Param> consumer)//正常嵌套 不带 AND 或者 OR apply(String applySql, Object... params)//拼接 sql,使用动态拼接参数不会有SQL注入的风险 last(String lastSql)//无视优化规则直接拼接到 sql 的最后,只能调用一次,多次调用以最后一次为准,有sql注入的风险,请谨慎使用 exists(String existsSql)//拼接 EXISTS ( sql语句 ) notExists(String notExistsSql)//拼接 NOT EXISTS ( sql语句 )
-
QueryWrapper
继承了AbstractWrapper
,并新增了select()
方法QueryWrapper(T entity)//在创建 QueryWrapper 对象时,可以传入一个实体类,默认是以 = 为条件 select(String... sqlSelect)//选择要查询的字段,例:select("id", "name", "age")
-
UpdateWrapper
继承了AbstractWrapper
,并新增了set()
和setSql()
方法UpdateWrapper(T entity)//在创建 UpdateWrapper 对象时,可以传入一个实体类,默认是以 = 为条件 set(String column, Object val)//SQL SET 字段; 例: set("name", "老李头") setSql(String sql)//设置 SET 部分 SQL; 例: setSql("name = '老李头'")
这里举几个例子:
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//SELECT name,id,age FROM user WHERE age BETWEEN ? AND ? AND ( name = ? ) OR email LIKE ?
queryWrapper.select("name", "id", "age")
.between("age", 20, 31)
.nested(i -> i.eq("name", "lele"))
.or()
.like("email", "@qq");
//SELECT id,name,age,email FROM user WHERE name like ? and age > ? limit 2
queryWrapper.select("id", "name", "age", "email")
.apply("name like {0} and age > {1}", "%l%", 19)
.last("limit 2");
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
//UPDATE user SET age=? WHERE name = ?
updateWrapper.set("age",23)
.eq("name", "lele");
六、常用配置
1. 表字段驼峰命名与下划线映射
mybatis-plus.configuration.mapUnderscoreToCamelCase
是否开启自动驼峰命名规则(camel case
)映射,即从经典数据库列名 A_COLUMN
(下划线命名) 到经典 Java 属性名 aColumn
(驼峰命名) 的类似映射。如果数据库的命名符合规则,则无需使用 @TableField 注解指定数据库字段名
- 类型:boolean
- 默认值:true(默认开启)
2. 打印SQL语句日志配置
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
七、自动填充插件
表中的字段如:创建时间、修改时间这些字段,可以使用下面两种方法来实现自动填充
1. 数据库级别
对数据库中这两个字段进行如下设置:
CREATE TABLE `mytest` (
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
在创建时间字段的时候
-
DEFAULT CURRENT_TIMESTAMP
:表示当插入数据的时候,该字段默认值为当前时间 -
ON UPDATE CURRENT_TIMESTAMP
:表示每次更新这条数据的时候,该字段都会更新成当前时间
2. 代码级别(使用MybatisPlus)
一般工作中不允许修改数据库,这里就可以使用MybatisPlus提供的方法,共两步:
-
在实体类中需要自动填充的字段上加入注解
@TableField(.. fill = FieldFill.INSERT)
// 字段添加填充内容 @TableField(fill = FieldFill.INSERT)//表示插入时自动填充 private Date createTime; @TableField(fill = FieldFill.INSERT_UPDATE)//表示插入和更新时自动填充 private Date updateTime;
-
编写处理器,实现元对象处理器接口:
com.baomidou.mybatisplus.core.handlers.MetaObjectHandler
@Slf4j @Component public class MyMetaObjectHandler implements MetaObjectHandler { @Override public void insertFill(MetaObject metaObject) { log.info("start insert fill ...."); this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐使用) this.fillStrategy(metaObject, "createTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug请升级到之后的版本如`3.3.1.8-SNAPSHOT`) /* 上面选其一使用,下面的已过时(注意 strictInsertFill 有多个方法,详细查看源码) */ //this.setFieldValByName("operator", "Jerry", metaObject); //this.setInsertFieldValByName("operator", "Jerry", metaObject); } @Override public void updateFill(MetaObject metaObject) { log.info("start update fill ...."); this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐使用) this.fillStrategy(metaObject, "updateTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug请升级到之后的版本如`3.3.1.8-SNAPSHOT`) /* 上面选其一使用,下面的已过时(注意 strictUpdateFill 有多个方法,详细查看源码) */ //this.setFieldValByName("operator", "Tom", metaObject); //this.setUpdateFieldValByName("operator", "Tom", metaObject); } }
八、乐观锁插件
以官方文档为主:乐观锁插件
MybatisPlus 实现乐观锁要两个步骤:
-
在实体类的字段上添加
@Version
注解注意:
- 支持的数据类型只有:
int
,Integer
,long
,Long
,Date
,Timestamp
,LocalDateTime
- 整数类型下
newVersion = oldVersion + 1
newVersion
会回写到entity
中- 仅支持
updateById(id)
与update(entity, wrapper)
方法
@Version private Integer version;
- 支持的数据类型只有:
-
添加一个拦截器
@Bean public OptimisticLockerInterceptor optimisticLockerInterceptor() { return new OptimisticLockerInterceptor(); }
小例子:
// 1、查询用户信息,这里查出来version为2
User user = userMapper.selectById(1);
// 2、修改用户信息
user.setName("一名小码农");
user.setAge("25");
// 3、执行更新操作
userMapper.updateById(user);
上面的代码相当于下面的 sql 语句:
# 先查询用户信息
select * from tbl_user where id=1;
# 更新
update tbl_user set name = '一名小码农', age = 25, version = 3 where id = 1 and version = 2
九、分页插件
官方文档:https://mp.baomidou.com/guide/page.html
-
配置一个分页拦截器:
PaginationInterceptor
://Spring boot方式 @Configuration public class MybatisPlusConfig { @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; } }
-
然后直接使用分页查询即可:
// 参数一:当前页 // 参数二:页面大小 Page<User> page = new Page<>(2, 5); userMapper.selectPage(page, null); //查询后的结果会放在传入的 Page 对象中 page.getRecords().forEach(System.out::println); //total是Page对象的属性,表示总条数 System.out.println(page.getTotal());
Page对象
Page 对象的属性:
字段名 | 字段类型 | 说明 | 默认值 |
---|---|---|---|
records | List<T> | 查询出的数据列表 | 空集合 |
total | long | 总数 | 0 |
size | long | 每页显示条数 | 10 |
current | long | 当前页 | 1 |
orders | List<OrderItem> | 排序字段信息 | 空集合 |
optimizeCountSql | boolean | 自动优化 COUNT SQL | true |
isSearchCount | boolean | 是否进行 count 查询 | true |
hitCount | boolean | 是否命中count缓存 | false |
常用 Page 对象方法:
方法名 | 返回值 | 说明 |
---|---|---|
hasPrevious() | boolean | 是否存在上一页 |
hasNext() | boolean | 是否存在下一页 |
十、逻辑删除
3.3.0 版本之前的逻辑删除需要添加拦截器,3.3.0 版本开始,只需要做一些简单的配置即可
- application.yml 加入配置:
mybatis-plus: global-config: db-config: logic-delete-field: flag #全局逻辑删除字段值 3.3.0开始支持,详情看下面。 logic-delete-value: 1 # 逻辑已删除值(默认为 1) logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
- 实体类字段上加上
@TableLogic
注解@TableLogic private Integer deleted;
逻辑删除,最终操作数据库的 SQL 语句都是更新操作
查询的时候,MybatisPlus 会自动拼接上 @TableLogic 修饰的字段,这样逻辑删除的数据就不会显示出来了
十一、代码生成
代码生成可以使用官方的代码:https://mp.baomidou.com/guide/generator.html
也可以使用 Easycode 来生成代码:https://blog.csdn.net/leisurelen/article/details/103930429/
也可以使用下面的代码用来生成代码:
- 添加代码生成依赖:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.3.2</version>
</dependency>
- 使用代码生成器(里面有的地方需要根据实际情况修改)
// 代码自动生成器
class GeneratorCodeTest {
public static void main(String[] args) {
// 需要构建一个 代码自动生成器 对象
AutoGenerator mpg = new AutoGenerator();
// 配置策略
// 1、全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath + "/src/main/java");
gc.setAuthor("狂神说");
gc.setOpen(false);
gc.setFileOverride(false); // 是否覆盖
gc.setServiceName("%sService"); // 去Service的I前缀
gc.setIdType(IdType.ID_WORKER);
gc.setDateType(DateType.ONLY_DATE);
gc.setSwagger2(true);
mpg.setGlobalConfig(gc);
//2、设置数据源
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/kuang_community? useSSL = false & useUnicode = true & characterEncoding = utf - 8 & serverTimezone = GMT % 2B8");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("123456");
dsc.setDbType(DbType.MYSQL);
mpg.setDataSource(dsc);
//3、包的配置
PackageConfig pc = new PackageConfig();
pc.setModuleName("blog");
pc.setParent("com.kuang");
pc.setEntity("entity");
pc.setMapper("mapper");
pc.setService("service");
pc.setController("controller");
mpg.setPackageInfo(pc);
//4、策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setInclude("blog_tags", "course", "links", "sys_settings", "user_record", "user_say"); // 设置要映射的表名
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setEntityLombokModel(true); // 自动lombok;
strategy.setLogicDeleteFieldName("deleted");
// 自动填充配置
TableFill gmtCreate = new TableFill("gmt_create", FieldFill.INSERT);
TableFill gmtModified = new TableFill("gmt_modified", FieldFill.INSERT_UPDATE);
ArrayList<TableFill> tableFills = new ArrayList<>();
tableFills.add(gmtCreate);
tableFills.add(gmtModified);
strategy.setTableFillList(tableFills);
// 乐观锁
strategy.setVersionFieldName("version");
strategy.setRestControllerStyle(true);
strategy.setControllerMappingHyphenStyle(true); //localhost:8080 / hello_id_2
mpg.setStrategy(strategy);
mpg.execute(); //执行
}
}
十二、spring-boot项目中手动注入mybatis-plus
前提:项目中用的包和 mybatis-plus-boot-starter
依赖冲突,只能引入 mybatis-plus
依赖包,然后手动注入
- 引入依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>3.0.5</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.45</version>
</dependency>
-
设置配置文件
-
MybatisPlusProperties 文件
import com.baomidou.mybatisplus.core.MybatisConfiguration; import com.baomidou.mybatisplus.core.config.GlobalConfig; import com.baomidou.mybatisplus.core.toolkit.GlobalConfigUtils; import com.snbc.bbpf.component.core.context.properties.ConfigurationProperties; import com.snbc.bbpf.component.core.context.properties.NestedConfigurationProperty; import org.apache.ibatis.session.ExecutorType; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; import java.io.IOException; import java.util.Optional; import java.util.Properties; import java.util.stream.Stream; /** * Configuration properties for MyBatis. */ @ConfigurationProperties(prefix = "mybatis-plus") @Data public class MybatisPlusProperties { private static final ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver(); /** * Location of MyBatis xml config file. */ private String configLocation; /** * Locations of MyBatis mapper files. */ private String[] mapperLocations; /** * Packages to search type aliases. (Package delimiters are ",; \t\n") */ private String typeAliasesPackage; /** * The super class for filtering type alias. * If this not specifies, the MyBatis deal as type alias all classes that searched from typeAliasesPackage. */ private Class<?> typeAliasesSuperType; /** * Packages to search for type handlers. (Package delimiters are ",; \t\n") */ private String typeHandlersPackage; /** * Packages to search for type enums. (Package delimiters are ",; \t\n") */ private String typeEnumsPackage; /** * Indicates whether perform presence check of the MyBatis xml config file. */ private boolean checkConfigLocation; /** * Execution mode for {@link org.mybatis.spring.SqlSessionTemplate}. */ private ExecutorType executorType; /** * Externalized properties for MyBatis configuration. */ private Properties configurationProperties; /** * A Configuration object for customize default settings. If {@link #configLocation} * is specified, this property is not used. */ @NestedConfigurationProperty private MybatisConfiguration configuration; /** * Global Config */ @NestedConfigurationProperty private GlobalConfig globalConfig = GlobalConfigUtils.defaults(); public Resource[] resolveMapperLocations() { return Stream.of(Optional.ofNullable(this.mapperLocations).orElse(new String[0])) .flatMap(location -> Stream.of(getResources(location))) .toArray(Resource[]::new); } private Resource[] getResources(String location) { try { return resourceResolver.getResources(location); } catch (IOException e) { return new Resource[0]; } } }
-
MyBatisLocalConfiguration 配置文件,手动注入
import com.baomidou.mybatisplus.core.MybatisConfiguration; import com.baomidou.mybatisplus.core.config.GlobalConfig; import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator; import com.baomidou.mybatisplus.core.injector.ISqlInjector; import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean; import com.snbc.bbpf.component.configure.mybatis.ConfigurationCustomizer; import com.snbc.bbpf.component.configure.mybatis.PlatformtVFS; import com.snbc.bbpf.component.core.context.properties.EnableConfigurationProperties; import org.apache.ibatis.mapping.DatabaseIdProvider; import org.apache.ibatis.plugin.Interceptor; import org.apache.ibatis.session.SqlSessionFactory; import org.springframework.beans.factory.ObjectProvider; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ResourceLoader; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import javax.sql.DataSource; import java.util.List; /** * MyBatis本地配置类 */ @Configuration @EnableConfigurationProperties(MybatisPlusProperties.class) public class MyBatisLocalConfiguration { /** * MyBatis 配置对象 */ private final MybatisPlusProperties properties; /** * Interceptor */ private final Interceptor[] interceptors; /** * ResourceLoader */ private final ResourceLoader resourceLoader; /** * 数据库配置对象 */ private final DatabaseIdProvider databaseIdProvider; /** * ApplicationContext上下文 */ private final ApplicationContext applicationContext; /** * ConfigurationCustomizer集合 */ private final List<ConfigurationCustomizer> configurationCustomizers; /** * 获取MyBatis配置 * * @param properties * @param interceptorsProvider * @param resourceLoader * @param databaseIdProvider * @param applicationContext * @param configurationCustomizersProvider */ public MyBatisLocalConfiguration(MybatisPlusProperties properties, ObjectProvider<Interceptor[]> interceptorsProvider, ResourceLoader resourceLoader, ObjectProvider<DatabaseIdProvider> databaseIdProvider, ApplicationContext applicationContext, ObjectProvider<List<ConfigurationCustomizer>> configurationCustomizersProvider) { this.properties = properties; this.interceptors = interceptorsProvider.getIfAvailable(); this.resourceLoader = resourceLoader; this.databaseIdProvider = databaseIdProvider.getIfAvailable(); this.applicationContext = applicationContext; this.configurationCustomizers = configurationCustomizersProvider.getIfAvailable(); } /** * 获取SqlSessionFactory * * @param dataSource * @return SqlSessionFactory * @throws Exception */ @Bean public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean(); // 数据源 factory.setDataSource(dataSource); factory.setVfs(PlatformtVFS.class); if (StringUtils.hasText(this.properties.getConfigLocation())) { factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation())); } // mybatis-plus configuration MybatisConfiguration configuration = mybatisplusConfig(); factory.setConfiguration(configuration); if (this.properties.getConfigurationProperties() != null) { factory.setConfigurationProperties(this.properties.getConfigurationProperties()); } if (!ObjectUtils.isEmpty(this.interceptors)) { factory.setPlugins(this.interceptors); } if (this.databaseIdProvider != null) { factory.setDatabaseIdProvider(this.databaseIdProvider); } if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) { factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage()); } if (StringUtils.hasLength(this.properties.getTypeEnumsPackage())) { factory.setTypeEnumsPackage(this.properties.getTypeEnumsPackage()); } if (this.properties.getTypeAliasesSuperType() != null) { factory.setTypeAliasesSuperType(this.properties.getTypeAliasesSuperType()); } if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) { factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage()); } if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) { factory.setMapperLocations(this.properties.resolveMapperLocations()); } GlobalConfig globalConfig = mybatisplusGlobalConfig(); factory.setGlobalConfig(globalConfig); return factory.getObject(); } /** * mybatis-plus 配置信息 * * @return 配置信息 */ private MybatisConfiguration mybatisplusConfig() { MybatisConfiguration configuration = this.properties.getConfiguration(); if (configuration == null && !StringUtils.hasText(this.properties.getConfigLocation())) { configuration = new MybatisConfiguration(); } if (configuration != null && !CollectionUtils.isEmpty(this.configurationCustomizers)) { for (ConfigurationCustomizer customizer : this.configurationCustomizers) { customizer.customize(configuration); } } return configuration; } /** * 获取GlobalConfig配置 * * @return GlobalConfig */ private GlobalConfig mybatisplusGlobalConfig() { GlobalConfig globalConfig = this.properties.getGlobalConfig(); // 注入填充器 if (this.applicationContext.getBeanNamesForType(MetaObjectHandler.class, false, false).length > 0) { MetaObjectHandler metaObjectHandler = this.applicationContext.getBean(MetaObjectHandler.class); globalConfig.setMetaObjectHandler(metaObjectHandler); } // 注入主键生成器 if (this.applicationContext.getBeanNamesForType(IKeyGenerator.class, false, false).length > 0) { IKeyGenerator keyGenerator = this.applicationContext.getBean(IKeyGenerator.class); globalConfig.getDbConfig().setKeyGenerator(keyGenerator); } // 注入SQL注入器 if (this.applicationContext.getBeanNamesForType(ISqlInjector.class, false, false).length > 0) { ISqlInjector iSqlInjector = this.applicationContext.getBean(ISqlInjector.class); globalConfig.setSqlInjector(iSqlInjector); } return globalConfig; } }
- 添加插件
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector; import com.baomidou.mybatisplus.core.injector.ISqlInjector; import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; import com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor; import org.mybatis.spring.annotation.MapperScan; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration @MapperScan(value = {"com.snbc.giftvoucher.ecoupon.dao"}) public class MyBatisPlusConfiguration { /** * SQL性能插件 * * @return PerformanceInterceptor */ @Bean public PerformanceInterceptor performanceInterceptor() { return new PerformanceInterceptor(); } /** * 分页查询插件 * * @return PaginationInterceptor */ @Bean public PaginationInterceptor paginationInterceptor() { return new PaginationInterceptor(); } /** * SQL 默认注入器 * * @return ISqlInjector */ @Bean public ISqlInjector sqlInjector() { return new DefaultSqlInjector(); } }
-
-
配置 application.properties 文件
mybatis-plus.mapper-locations = classpath:mapping/**/*.xml
-
mybatis-plus 就可以使用了