解決SpringBoot整合MybatisPlus分模塊管理遇到的bug
前言
這個Bug前前後後折騰瞭兩天才找到答案,雖說不是完全兩天的工作時間在調試這個問題,但是過程也確實曲折,所以做一下記錄,也當做一次自我反省
背景
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>
項目分模塊結構
之前一直停留在 SpringBoot 整合其他框架做一些小項目,所以都是把代碼放在一個工程,也沒有進行分模塊管理。
由於公司打算開發新產品,我想嘗試在 SpringBoot 的項目來做分模塊的開發(Maven工程),並且用 MyBatis-Plus 來做持久層框架,也就是將 SpringBoot 做 web模塊, 實體跟Mapper 拆分到 persistence模塊,並將 mapper.xml 文件放在 persistence模塊 的 resources/mapper 目錄下。
在項目分模塊完成之後,並進行代碼移植時並沒有發現問題,因為此時並不需要調用到自定義 mapper.xml 中的 sql 查詢數據庫。但隨著一步一步的完善代碼,也開始需要用到 mapper.xml 的 sql 查詢,此時,在調試時,發現瞭如下錯誤:
即,報找不到對應的 sql
排查原因
排除 mapper.xml 書寫錯誤
首先排除 mapper.xml 中 namespace 或 sql 的 id 寫錯,因為我的開發工具下載瞭 MybatisX 的插件,mapper.java 與 mapper.xml 都有插件的小圖標,如下圖所示,
懷疑:分模塊導致
其次,在先前我已經整合過 SpringBoot 與 MyBatis-Plus 單項目的工程,並沒有這個問題,所以,我懷疑是因為 分模塊導致的原因 導致的,所以,我想 分模塊跟不分模塊的工程 有區別?
區別就是,不分模塊 mapper.xml 文件就在項目 classes 下的 mapper 中,而分模塊後, mapper.xml 文件就在 persistence模塊打出來的 jar 中 。
錯誤思路:修改pom文件配置resources目錄
所以,發現瞭這點之後,就開始必應解決方案,但是剛開始我的思路是 錯誤的,我以為項目打包之後,沒有把 persistence模塊的 resources 下 的 mapper 目錄打包進 jar 中 。浪費瞭一些時間之後,我才想清楚應該先去 persistence模塊 打出來的 jar 中確認有沒有將 resources 下的 mapper/mapper.xml 打包進去。
懷疑:Spring Resource時沒有加載 jar 中的 mapper.xml
上面的問題教瞭自己一課,眼見為實 ,雖然解決 Bug 的過程中,合理的猜測是必要的,但是在有限的結果集中,驗證排除一些錯誤的思路更為重要。就像,經常有人會問我,“為什麼我運行老是報找不到類的錯誤”,我就說那你到 tomcat 的發佈路徑上看一下 jar 包有沒有發不上去,這其實是一個道理的。
回到問題,為什麼Spring Resource時沒有加載 jar 中的 mapper.xml ?必應尋找解決方案,在必應的過程中我才想起瞭 Spring 的 Resource 加載文件, classpath 與 classpath* 的區別,好久沒有自己手寫搭項目,把這個給忘記瞭。
所以,此時我確信將 application.xml 中 mybatis-plus.mapper-locations 的值改為 classpath*:mapper/*Mapper.xml 即可,如下
#mapper plus mybatis-plus: mapper-locations: classpath*:mapper/*Mapper.xml
懷疑:SpringBoot 跟 MyBatis-Plus 整合的配置哪裡不對嗎?
上面的配置修改之後,重新運行,還是報同樣的錯!!!
What The Fuck!!!因為我覺得這個 bug 就是由於 classpath:mapper/*Mapper.xml Spring 的 Resource 隻能掃描當前應用中的 classpath 下的 mapper 目錄的 mapper.xml 的文件,所以,我又重新必應瞭 SpringBoot 與 Mybati-plus 的整合配置 ,說到底還是對這個框架不瞭解,導致走瞭不少彎路,而且在出問題的時候,沒有堅信自己的判斷,而不斷的嘗試必應出來的結果,使得又浪費瞭一些時間在這個問題上。
最後必應瞭一圈後,還是沒有找到解決方案,而且與此相關的問題文章也不多, 我開始迷茫跟急躁瞭,畢竟已經浪費瞭這麼多的時間,我還是決定先驗證一下我前面深信的東西—- Spring 的 Resource 加載文件, classpath 與 classpath* 的區別 ,所以,我決定自己創建 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); //添加分頁功能 sqlSessionFactory.setPlugins(new Interceptor[]{ paginationInterceptor() }); return sqlSessionFactory.getObject(); }
結果是運行通過瞭!!不過,這也是理所當然的,這就說明瞭我在 application.xml 中 mybatis-plus 的配置沒生效,相當於又回到瞭上一個問題。到瞭這裡,我才想到去看 mybatis-plus-boot-starter 裡面的源碼!!
沒想到的是,源碼相當容易看,首先,jar 包的目錄結構如下,看名字直接選擇看 MybatisPlusAutoConfiguration 這個配置類
打開 MybatisPlusAutoConfiguration 的源碼,直接看 SqlSessionFactory 的創建,如下,在設置 mapper-locations 的判斷處,打下斷點,進行調試
並且將前面自定義創建的 SqlSessionFactory 的代碼註釋掉,application.yml 中配置 mapper-locations: classpath*:mapper/*Mapper.xml ,重新運行,進行源碼調試,發現上圖斷點的邏輯,沒有進到 if 的判斷中去,調試的 MybatisPlusProperties 對象結果如下,
!!!What The Fuck!!!我配置的明明是 classpath*:mapper/*Mapper.xml ,怎麼變成瞭 classpath:mapper/*Mapper.xml 可恨的是,我的思路有繞彎瞭!!!
懷疑:yml 的配置語法對 classpath*:mapper/*Mapper.xml 解析有問題
我都服瞭我自己瞭,但確實是這次修改讓我找到瞭最後的答案,將原本的配置寫法改成瞭數組,寫法如下,
#mapper plus mybatis-plus: mapper-locations: [classpath*:mapper/*Mapper.xml]
因為對這種配置格式也沒去深究,之前都是一對一的配置項,沒有嘗試過數組的寫法,所以上來就運行報錯瞭,但是報的是 application.yml 的語法格式有誤。所以,將值加上引號括起來,變成
#mapper plus mybatis-plus: mapper-locations: ["classpath*:mapper/*Mapper.xml"]
重新運行,發現竟然通過瞭!!!源碼調試的 mapperLocations 的值也是 classpath*:mapper/*Mapper.xml ,此時我以為找到瞭問題的所在瞭,就是 yml 的配置語法對 classpath*:mapper/*Mapper.xml 解析有問題 我也對此深信不疑。
結論:開發工具沒有同步配置
在沒寫這筆記前,我還深信問題就是 yml 的語法對值帶有 冒號 的解析時,需要對值用 引號 包起來。但是在寫筆記做記錄的過程中,需要還原場景,在調試的時候,發現並沒有說 需要對帶有冒號的值加上引號包起來 ,這時我才想起來,會不會是 開發工具的問題,在運行的時候,沒有把修改的配置文件同步上去 。經過多次的調試,也證明瞭這點,有時候項目跑太久,開發工具就會突然出來發難。
搞瞭半天, 在 application.yml 的配置 classpath*:mapper/*Mapper.xml 是有效的!!!有效的!!!有效的!!! 相當於開發工具的作祟讓我白白浪費瞭2天時間,但是期間也發現瞭自身的一下問題,太久沒有遇到錯誤,一味的相信搜索引擎而不去思考,最後還差點 用錯誤的認識,否定瞭原本正確的東西 。
#mapper plus mybatis-plus: mapper-locations: classpath*:mapper/*Mapper.xml
在發現 application.yml配置修改後沒生效的第一時間,我就應該檢查發佈路徑的文件,或者去調試源碼。中間浪費太多的時間陷入盲目的必應搜索答案,做筆記反省一下自己,安定就會退步,堅持學習,永遠不要放棄思考。
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- SpringBoot+Mybatis實現Mapper接口與Sql綁定幾種姿勢
- Springboot項目中內嵌sqlite數據庫的配置流程
- springboot配置mybatis和事務管理方式
- 小項目改造快速引入 mybatis的流程分析
- mybatis那些約定的配置你真的都瞭解嗎(經驗總結)