Mybatis Plus注入全局操作踩坑

起源

最近在学习mybatis plus(下文简称mp)的进阶操作,有一个自定义全局操作。

简单来说就是你在mapper中定义一个方法,常规的方法就是在xml文件中写具体sql或者方法上面打注解,注解里面写具体sql实现
初次之外,mp还支持一种注入方式。这种方式类似mp提供的BaseMapper,并没有直接在xml中写sql,而是在mp启动的时候注入sql
在实际项目使用过程中,遇到一些小问题,花费了不少时间,查阅不少资料才解决,故此记录下。
先交代下使用的mp坐标:

<dependency>
    <groupId>com.baomidou</groupId>
       <artifactId>mybatisplus-spring-boot-starter</artifactId>
       <version>1.0.5</version>
</dependency>

现场还原

定义自己的Mapper

public interface CustomBaseMapper<T> extends BaseMapper<T> {
    List<Integer> customCount(
        @Param("city_code") String cityCode, 
        @Param("company_code") String companyCode);
}

继承AutoSqlInjector

public class CustomSqlInjector extends AutoSqlInjector {

    private static final String CUSTOM_COUNT = "select count(*) from %1$s where city_code = ‘all‘ union all"
            + " select count(*) from %1$s where city_code = #{city_code} and company_code = ‘all‘ union all"
            + " select count(*) from %1$s where city_code = #{city_code} and company_code = #{company_code}";

    @Override
    public void inject(Configuration configuration, MapperBuilderAssistant builderAssistant, Class<?> mapperClass, Class<?> modelClass, TableInfo table) {
        String sql = String.format(CUSTOM_COUNT, table.getTableName());
        String method = "customCount";
        SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
        this.addSelectMappedStatement(mapperClass, method, sqlSource, Integer.class, table);
    }
}

到这里我们基本写完,最后一步就是在Spring中注入CustomSqlInjector这个Bean

@Bean
public ISqlInjector sqlInjector() {
    return new CustomSqlInjector();
}

实际使用时候,如果想获得自定义方法customCount,只需要继承CustomBaseMapper即可。

踩坑一

项目一启动就报错,定睛一看:

sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to java.lang.Class异常解决方法

这个报错有点莫名奇妙,去官网搜索一下,发现作者给了解决方案:

MapperScan 需要排除 com.baomidou.mybatisplus.mapper.BaseMapper 类 及其 子类(自定义公共 Mapper)

这句话当时一下子没看明白,简单浏览了下MapperScan注解,发现好像并没有排除相关的属性。后来百度了下,在一份博客下面的评论找到了答案。

今天我也遇到类似的问题,是UserMapper文件继承了CommonMapper文件,都放在Mapper包下,然后就出现了父子Bean的问题了,将commonMapper文件从CommonMapper挪出来后,就可以了

事后想了下应该跟官网作者说的是一个意思,只是下面这个更通俗易懂。

踩坑二

上面说到,需要注入自己的CustomSqlInjector。常规操作就是在标识 @Configuration的类里写上一个方法即可:

@Bean
public ISqlInjector sqlInjector() {
    return new CustomSqlInjector();
}

实际看来效果可能如下,但这样启动发现自定义操作并没有注入进去。经过一番摸索,去翻阅了官网2.x的文档,跳转到自定义全局操作 一节。
当时文档上写的注入方式是用配置文件完成:

<!-- 定义 MP 全局策略,安装集成文档部分结合 -->
<bean id="globalConfig" class="com.baomidou.mybatisplus.entity.GlobalConfiguration">
    .....

  <!-- 自定义注入 deleteAll 方法  -->
  <property name="sqlInjector" ref="mySqlInjector" />
</bean>

<!-- 自定义注入器 -->
<bean id="mySqlInjector" class="com.baomidou.test.MySqlInjector" />

定睛一看,写在GlobalConfiguration这个标签下,于是我想到是否可以尝试在application.yml文件进行同样的配置:

mybatis-plus:
  mapper-locations:
    - classpath*:mapper/*.xml
  typeAliasesPackage: com.test.tao.*.model.domain
  global-config:
    id-type: 0
    field-strategy: 2
    db-column-underline: true
    sql-injector: com.test.tao.operation.inject.CustomSqlInjector
  configuration:
    map-underscore-to-camel-case: true
    cache-enabled: false

经过这样一配置,发现成功了,注入成功了。

虽然解决方案很简单,但那天晚上缺尝试了很久。

后来我看了mp官方给的示例,注入方式改变了,简化了很多。其实把mp官方给的demo来下来调试运行下,可以学到不少新的技巧,值得尝试。