MyBatisPlus学习笔记

一、概述

虽然mybatis可以直接在xml中通过SQL语句操作数据库,很是灵活。但正因其操作都要通过SQL语句进行,就必须写大量的xml文件,很是麻烦。mybatis-plus就很好的解决了这个问题。

官方的定义:Mybatis-Plus(简称MP)是一个 Mybatis 的增强工具,在 Mybatis 的基础上只做增强不做改变,为简化开发、提高效率而生。这是官方给的定义,关于mybatis-plus的更多介绍及特性,可以参考mybatis-plus官网。那么它是怎么增强的呢?其实就是它已经封装好了一些crud方法,我们不需要再写xml了,直接调用这些方法就行,就类似于JPA。

二、准备工作

这里使用的是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(表名注解)

属性类型必须指定默认值描述
valueString“”指定表名(当表名与实体类名不一致(不满足驼峰和下划线的映射关系)时,用该属性指定实体类对应的表名)

2. @TableId(主键注解)

属性类型必须指定默认值描述
valueString“”主键字段名
typeEnumIdType.NONE主键类型

IdType(主键类型)

描述
AUTO数据库ID自增
NONE该类型为未设置主键类型(将跟随全局)
INPUT插入前手动输入
ID_WORKER全局唯一ID (idWorker、雪花算法)(只有当插入对象ID 为空,才自动填充)(默认
UUID全局唯一ID (UUID)(只有当插入对象ID 为空,才自动填充)
ID_WORKER_STR字符串全局唯一ID (idWorker 的字符串表示)(只有当插入对象ID 为空,才自动填充)

3. @TableField(非主键字段注解)

属性类型必须指定默认值描述
valueString“”指定数据库字段名(与@TableName注解中的value属性类似,只不过这个是指定非主键字段名)
existbooleantrue是否为数据库表字段
fillEnumFieldFill.DEFAULT字段自动填充策略(可以设置更新或者插入时自动填充)

四、BaseMapper<T>中的方法

1. 插入

// 插入一条记录
int insert(T entity);
  • 参数说明:

    类型参数名描述
    Tentity实体对象

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);
  • 参数说明:

    类型参数名描述
    Wrapperwrapper实体对象封装操作类(可以为 null)
    Collection<? extends Serializable>idList主键ID列表(不能为 null 以及 empty)
    Serializableid主键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);
  • 参数说明:

    类型参数名描述
    Tentity实体对象 (set 条件值,可为 null)
    WrapperupdateWrapper实体对象封装操作类(可以为 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);
    
  • 参数说明:

    类型参数名描述
    Serializableid主键ID
    WrapperqueryWrapper实体对象封装操作类(可以为 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

  1. 常用的 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语句 )
    
  2. QueryWrapper 继承了 AbstractWrapper ,并新增了 select() 方法

    QueryWrapper(T entity)//在创建 QueryWrapper 对象时,可以传入一个实体类,默认是以 = 为条件
    
    select(String... sqlSelect)//选择要查询的字段,例:select("id", "name", "age")
    
  3. 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提供的方法,共两步:

  1. 在实体类中需要自动填充的字段上加入注解 @TableField(.. fill = FieldFill.INSERT)

    // 字段添加填充内容
    @TableField(fill = FieldFill.INSERT)//表示插入时自动填充
    private Date createTime;
    
    @TableField(fill = FieldFill.INSERT_UPDATE)//表示插入和更新时自动填充
    private Date updateTime;
    
  2. 编写处理器,实现元对象处理器接口: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 实现乐观锁要两个步骤:

  1. 在实体类的字段上添加 @Version 注解

    注意:

    • 支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
    • 整数类型下 newVersion = oldVersion + 1
    • newVersion 会回写到 entity
    • 仅支持 updateById(id)update(entity, wrapper) 方法
    @Version
    private Integer version;
    
  2. 添加一个拦截器

    @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

  1. 配置一个分页拦截器: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;
        }
    }
    
  2. 然后直接使用分页查询即可:

    // 参数一:当前页
    // 参数二:页面大小
    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 对象的属性:

字段名字段类型说明默认值
recordsList<T>查询出的数据列表空集合
totallong总数0
sizelong每页显示条数10
currentlong当前页1
ordersList<OrderItem>排序字段信息空集合
optimizeCountSqlboolean自动优化 COUNT SQLtrue
isSearchCountboolean是否进行 count 查询true
hitCountboolean是否命中count缓存false

常用 Page 对象方法:

方法名返回值说明
hasPrevious()boolean是否存在上一页
hasNext()boolean是否存在下一页

十、逻辑删除

3.3.0 版本之前的逻辑删除需要添加拦截器,3.3.0 版本开始,只需要做一些简单的配置即可

  1. 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)
    
  2. 实体类字段上加上@TableLogic注解
    @TableLogic
    private Integer deleted;
    

逻辑删除,最终操作数据库的 SQL 语句都是更新操作
查询的时候,MybatisPlus 会自动拼接上 @TableLogic 修饰的字段,这样逻辑删除的数据就不会显示出来了

十一、代码生成

代码生成可以使用官方的代码:https://mp.baomidou.com/guide/generator.html

也可以使用 Easycode 来生成代码:https://blog.csdn.net/leisurelen/article/details/103930429/

EasyCode插件的使用

也可以使用下面的代码用来生成代码:

  1. 添加代码生成依赖:
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.3.2</version>
</dependency>
  1. 使用代码生成器(里面有的地方需要根据实际情况修改)
// 代码自动生成器
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 依赖包,然后手动注入

  1. 引入依赖
<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>
  1. 设置配置文件

    1. 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];
              }
          }
      
      }
      
    2. 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;
          }
      
      }
      
      1. 添加插件
      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();
          }
      }
      
  2. 配置 application.properties 文件

    mybatis-plus.mapper-locations = classpath:mapping/**/*.xml
    
  3. mybatis-plus 就可以使用了

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值