解決SpringBoot整合MybatisPlus分模塊管理遇到的bug
前言
這個(gè)Bug前前后后折騰了兩天才找到答案,雖說(shuō)不是完全兩天的工作時(shí)間在調(diào)試這個(gè)問(wèn)題,但是過(guò)程也確實(shí)曲折,所以做一下記錄,也當(dāng)做一次自我反省
背景
SpringBoot 與 MyBatis-Plus 的 pom 依賴
<!-- SpringBoot 版本 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<!-- MyBatis-plus 版本 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.0</version>
</dependency>
項(xiàng)目分模塊結(jié)構(gòu)

之前一直停留在 SpringBoot 整合其他框架做一些小項(xiàng)目,所以都是把代碼放在一個(gè)工程,也沒(méi)有進(jìn)行分模塊管理。
由于公司打算開(kāi)發(fā)新產(chǎn)品,我想嘗試在 SpringBoot 的項(xiàng)目來(lái)做分模塊的開(kāi)發(fā)(Maven工程),并且用 MyBatis-Plus 來(lái)做持久層框架,也就是將 SpringBoot 做 web模塊, 實(shí)體跟Mapper 拆分到 persistence模塊,并將 mapper.xml 文件放在 persistence模塊 的 resources/mapper 目錄下。
在項(xiàng)目分模塊完成之后,并進(jìn)行代碼移植時(shí)并沒(méi)有發(fā)現(xiàn)問(wèn)題,因?yàn)榇藭r(shí)并不需要調(diào)用到自定義 mapper.xml 中的 sql 查詢數(shù)據(jù)庫(kù)。但隨著一步一步的完善代碼,也開(kāi)始需要用到 mapper.xml 的 sql 查詢,此時(shí),在調(diào)試時(shí),發(fā)現(xiàn)了如下錯(cuò)誤:

即,報(bào)找不到對(duì)應(yīng)的 sql
排查原因
排除 mapper.xml 書(shū)寫(xiě)錯(cuò)誤
首先排除 mapper.xml 中 namespace 或 sql 的 id 寫(xiě)錯(cuò),因?yàn)槲业拈_(kāi)發(fā)工具下載了 MybatisX 的插件,mapper.java 與 mapper.xml 都有插件的小圖標(biāo),如下圖所示,

懷疑:分模塊導(dǎo)致
其次,在先前我已經(jīng)整合過(guò) SpringBoot 與 MyBatis-Plus 單項(xiàng)目的工程,并沒(méi)有這個(gè)問(wèn)題,所以,我懷疑是因?yàn)?分模塊導(dǎo)致的原因 導(dǎo)致的,所以,我想 分模塊跟不分模塊的工程 有區(qū)別?
區(qū)別就是,不分模塊 mapper.xml 文件就在項(xiàng)目 classes 下的 mapper 中,而分模塊后, mapper.xml 文件就在 persistence模塊打出來(lái)的 jar 中 。
錯(cuò)誤思路:修改pom文件配置resources目錄
所以,發(fā)現(xiàn)了這點(diǎn)之后,就開(kāi)始必應(yīng)解決方案,但是剛開(kāi)始我的思路是 錯(cuò)誤的,我以為項(xiàng)目打包之后,沒(méi)有把 persistence模塊的 resources 下 的 mapper 目錄打包進(jìn) jar 中 。浪費(fèi)了一些時(shí)間之后,我才想清楚應(yīng)該先去 persistence模塊 打出來(lái)的 jar 中確認(rèn)有沒(méi)有將 resources 下的 mapper/mapper.xml 打包進(jìn)去。

懷疑:Spring Resource時(shí)沒(méi)有加載 jar 中的 mapper.xml
上面的問(wèn)題教了自己一課,眼見(jiàn)為實(shí) ,雖然解決 Bug 的過(guò)程中,合理的猜測(cè)是必要的,但是在有限的結(jié)果集中,驗(yàn)證排除一些錯(cuò)誤的思路更為重要。就像,經(jīng)常有人會(huì)問(wèn)我,“為什么我運(yùn)行老是報(bào)找不到類的錯(cuò)誤”,我就說(shuō)那你到 tomcat 的發(fā)布路徑上看一下 jar 包有沒(méi)有發(fā)不上去,這其實(shí)是一個(gè)道理的。
回到問(wèn)題,為什么Spring Resource時(shí)沒(méi)有加載 jar 中的 mapper.xml ?必應(yīng)尋找解決方案,在必應(yīng)的過(guò)程中我才想起了 Spring 的 Resource 加載文件, classpath 與 classpath* 的區(qū)別,好久沒(méi)有自己手寫(xiě)搭項(xiàng)目,把這個(gè)給忘記了。

所以,此時(shí)我確信將 application.xml 中 mybatis-plus.mapper-locations 的值改為 classpath*:mapper/*Mapper.xml 即可,如下
#mapper plus mybatis-plus: mapper-locations: classpath*:mapper/*Mapper.xml
懷疑:SpringBoot 跟 MyBatis-Plus 整合的配置哪里不對(duì)嗎?
上面的配置修改之后,重新運(yùn)行,還是報(bào)同樣的錯(cuò)!??!

What The Fuck?。?!因?yàn)槲矣X(jué)得這個(gè) bug 就是由于 classpath:mapper/*Mapper.xml Spring 的 Resource 只能掃描當(dāng)前應(yīng)用中的 classpath 下的 mapper 目錄的 mapper.xml 的文件,所以,我又重新必應(yīng)了 SpringBoot 與 Mybati-plus 的整合配置 ,說(shuō)到底還是對(duì)這個(gè)框架不了解,導(dǎo)致走了不少?gòu)澛罚以诔鰡?wèn)題的時(shí)候,沒(méi)有堅(jiān)信自己的判斷,而不斷的嘗試必應(yīng)出來(lái)的結(jié)果,使得又浪費(fèi)了一些時(shí)間在這個(gè)問(wèn)題上。
最后必應(yīng)了一圈后,還是沒(méi)有找到解決方案,而且與此相關(guān)的問(wèn)題文章也不多, 我開(kāi)始迷茫跟急躁了,畢竟已經(jīng)浪費(fèi)了這么多的時(shí)間,我還是決定先驗(yàn)證一下我前面深信的東西---- Spring 的 Resource 加載文件, classpath 與 classpath* 的區(qū)別 ,所以,我決定自己創(chuàng)建 sqlSessionFactory ,代碼如下
@Bean("sqlSessionFactory")
public SqlSessionFactory sqlSessionFactory() throws Exception {
MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
sqlSessionFactory.setDataSource(datasource);
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resolver.getResources("classpath*:mapper/*Mapper.xml");
sqlSessionFactory.setMapperLocations(resources);
MybatisConfiguration configuration = new MybatisConfiguration();
configuration.setJdbcTypeForNull(JdbcType.NULL);
configuration.setMapUnderscoreToCamelCase(true);
configuration.setCacheEnabled(false);
sqlSessionFactory.setConfiguration(configuration);
//添加分頁(yè)功能
sqlSessionFactory.setPlugins(new Interceptor[]{
paginationInterceptor()
});
return sqlSessionFactory.getObject();
}
結(jié)果是運(yùn)行通過(guò)了??!不過(guò),這也是理所當(dāng)然的,這就說(shuō)明了我在 application.xml 中 mybatis-plus 的配置沒(méi)生效,相當(dāng)于又回到了上一個(gè)問(wèn)題。到了這里,我才想到去看 mybatis-plus-boot-starter 里面的源碼??!
沒(méi)想到的是,源碼相當(dāng)容易看,首先,jar 包的目錄結(jié)構(gòu)如下,看名字直接選擇看 MybatisPlusAutoConfiguration 這個(gè)配置類

打開(kāi) MybatisPlusAutoConfiguration 的源碼,直接看 SqlSessionFactory 的創(chuàng)建,如下,在設(shè)置 mapper-locations 的判斷處,打下斷點(diǎn),進(jìn)行調(diào)試

并且將前面自定義創(chuàng)建的 SqlSessionFactory 的代碼注釋掉,application.yml 中配置 mapper-locations: classpath*:mapper/*Mapper.xml ,重新運(yùn)行,進(jìn)行源碼調(diào)試,發(fā)現(xiàn)上圖斷點(diǎn)的邏輯,沒(méi)有進(jìn)到 if 的判斷中去,調(diào)試的 MybatisPlusProperties 對(duì)象結(jié)果如下,

?。。hat The Fuck?。。∥遗渲玫拿髅魇?classpath*:mapper/*Mapper.xml ,怎么變成了 classpath:mapper/*Mapper.xml 可恨的是,我的思路有繞彎了?。。?/p>
懷疑:yml 的配置語(yǔ)法對(duì) classpath*:mapper/*Mapper.xml 解析有問(wèn)題
我都服了我自己了,但確實(shí)是這次修改讓我找到了最后的答案,將原本的配置寫(xiě)法改成了數(shù)組,寫(xiě)法如下,
#mapper plus mybatis-plus: mapper-locations: [classpath*:mapper/*Mapper.xml]
因?yàn)閷?duì)這種配置格式也沒(méi)去深究,之前都是一對(duì)一的配置項(xiàng),沒(méi)有嘗試過(guò)數(shù)組的寫(xiě)法,所以上來(lái)就運(yùn)行報(bào)錯(cuò)了,但是報(bào)的是 application.yml 的語(yǔ)法格式有誤。所以,將值加上引號(hào)括起來(lái),變成
#mapper plus mybatis-plus: mapper-locations: ["classpath*:mapper/*Mapper.xml"]
重新運(yùn)行,發(fā)現(xiàn)竟然通過(guò)了?。?!源碼調(diào)試的 mapperLocations 的值也是 classpath*:mapper/*Mapper.xml ,此時(shí)我以為找到了問(wèn)題的所在了,就是 yml 的配置語(yǔ)法對(duì) classpath*:mapper/*Mapper.xml 解析有問(wèn)題 我也對(duì)此深信不疑。
結(jié)論:開(kāi)發(fā)工具沒(méi)有同步配置
在沒(méi)寫(xiě)這筆記前,我還深信問(wèn)題就是 yml 的語(yǔ)法對(duì)值帶有 冒號(hào) 的解析時(shí),需要對(duì)值用 引號(hào) 包起來(lái)。但是在寫(xiě)筆記做記錄的過(guò)程中,需要還原場(chǎng)景,在調(diào)試的時(shí)候,發(fā)現(xiàn)并沒(méi)有說(shuō) 需要對(duì)帶有冒號(hào)的值加上引號(hào)包起來(lái) ,這時(shí)我才想起來(lái),會(huì)不會(huì)是 開(kāi)發(fā)工具的問(wèn)題,在運(yùn)行的時(shí)候,沒(méi)有把修改的配置文件同步上去 。經(jīng)過(guò)多次的調(diào)試,也證明了這點(diǎn),有時(shí)候項(xiàng)目跑太久,開(kāi)發(fā)工具就會(huì)突然出來(lái)發(fā)難。
搞了半天, 在 application.yml 的配置 classpath*:mapper/*Mapper.xml 是有效的?。?!有效的!??!有效的!??! 相當(dāng)于開(kāi)發(fā)工具的作祟讓我白白浪費(fèi)了2天時(shí)間,但是期間也發(fā)現(xiàn)了自身的一下問(wèn)題,太久沒(méi)有遇到錯(cuò)誤,一味的相信搜索引擎而不去思考,最后還差點(diǎn) 用錯(cuò)誤的認(rèn)識(shí),否定了原本正確的東西 。
#mapper plus mybatis-plus: mapper-locations: classpath*:mapper/*Mapper.xml
在發(fā)現(xiàn) application.yml配置修改后沒(méi)生效的第一時(shí)間,我就應(yīng)該檢查發(fā)布路徑的文件,或者去調(diào)試源碼。中間浪費(fèi)太多的時(shí)間陷入盲目的必應(yīng)搜索答案,做筆記反省一下自己,安定就會(huì)退步,堅(jiān)持學(xué)習(xí),永遠(yuǎn)不要放棄思考。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
spring boot創(chuàng)建項(xiàng)目包依賴問(wèn)題的解決
本篇文章主要介紹了spring boot創(chuàng)建項(xiàng)目包依賴問(wèn)題的解決,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-11-11
全排列算法-遞歸與字典序的實(shí)現(xiàn)方法(Java)
下面小編就為大家?guī)?lái)一篇全排列算法-遞歸與字典序的實(shí)現(xiàn)方法(Java) 。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-04-04
java中double強(qiáng)制轉(zhuǎn)換int引發(fā)的OOM問(wèn)題記錄
這篇文章主要介紹了java中double強(qiáng)制轉(zhuǎn)換int引發(fā)的OOM問(wèn)題記錄,本文給大家分享問(wèn)題排查過(guò)程,感興趣的朋友跟隨小編一起看看吧2024-10-10
java 實(shí)現(xiàn)黃金分割數(shù)的示例詳解
這篇文章主要介紹了java 實(shí)現(xiàn)黃金分割數(shù)的示例詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-02-02
Spring Cloud Feign統(tǒng)一設(shè)置驗(yàn)證token實(shí)現(xiàn)方法解析
這篇文章主要介紹了Spring Cloud Feign統(tǒng)一設(shè)置驗(yàn)證token實(shí)現(xiàn)方法解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08
Spring Cloud 2020.0.0正式發(fā)布再見(jiàn)了Netflix
這篇文章主要介紹了Spring Cloud 2020.0.0正式發(fā)布再見(jiàn)了Netflix,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12
Java動(dòng)態(tài)數(shù)組添加數(shù)據(jù)的方法與應(yīng)用示例
這篇文章主要介紹了Java動(dòng)態(tài)數(shù)組添加數(shù)據(jù)的方法,結(jié)合實(shí)例形式詳細(xì)分析了Java動(dòng)態(tài)數(shù)組的創(chuàng)建、添加、查找、打印等相關(guān)操作技巧,需要的朋友可以參考下2019-11-11
Java 如何繞過(guò)迭代器遍歷時(shí)的數(shù)據(jù)修改異常
這篇文章主要介紹了Java 繞過(guò)迭代器遍歷時(shí)的數(shù)據(jù)修改異常的方法,幫助大家更好的理解和學(xué)習(xí)使用Java,感興趣的朋友可以了解下2021-02-02

