起源
最近在學習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
來下來調試運行下,可以學到不少新的技巧,值得嘗試。