錯誤 org.apache.ibatis.binding.BindingException: Invalid bound statement (not found) 的出現,意味着項目須要xml文件來映射SQL語句,若是隻使用接口進行SQL映射,不在本文討論範圍內。html
個人項目的環境是IDEA下的Maven工程,而IDEA下的MAVEN工程中有一個特色就是,在src/main/java中,只有.java文件默認會被編譯,而xml文件不會被編譯。(出處)java
的確這樣的作法也比較符合Maven目錄框架的初衷:即在src/main/java中只存放.java的源碼文件。spring
在使用MyBatis Generator進行逆向生成時是能夠指定mapper接口和對應的xml文件的位置的,有的人也喜歡把它們指定在java目錄下的同一個包(如:src/main/java/com/abc/mapper)中,而我就喜歡指定在不一樣的目錄下(接口文件:src/main/java/com/abc/mapper,xml文件:scr/mian/resources/mapper)。咱們分開討論sql
1、Mapper接口文件和對應的XML在同一個目錄下數據庫
通常來講,接口文件和XML文件是同名一一對應的。apache
這種狀況就是要改變IDEA中MAVEN工程默認不編譯src/main/java中的xml文件的行爲,須要在maven的pom.xml中配置一個節點:api
<project> ...... <build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> </resources> </build> </project>
這樣IDEA就會對src/main/java中的xml文件進行編譯了。session
個人工程中進行相應的修改後,的確奏效了。mybatis
可是我項目中MyBatis的核心配置文件中,配置是空的,沒有指定任何xml的位置:app
<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> </configuration>
而後發現,在Spring容器中建立SqlSessionFactory的Bean時(在applicationContext-dao.xml中),就已經指定了Mapper接口的位置:
<!-- 讓spring管理sqlsessionfactory 使用mybatis和spring整合包中的 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 數據庫鏈接池 --> <property name="dataSource" ref="dataSource" /> <!-- 加載mybatis的全局核心配置文件 --> <property name="configLocation" value="classpath:mybatis/SqlMapConfig.xml" /> </bean> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.taotao.mapper" /> </bean>
在上面的配置中,若是我去掉第二個bean,應用就沒法正常啓動。報錯的內容大概是這樣:由於那些Mapper接口沒有被註冊爲Bean,因此在Service層中的相關類中的屬性的自動注入無法完成,由於找不到那些Mapper的bean。事實上,在Spring的配置文件中使用這個MapperScannerConfigurer類我也是第一次碰到,查了一下,這個類就是進行Bean的定義工做——「從接口的基礎包開始遞歸搜索,並將它們註冊爲MapperFactoryBean。 請注意,僅註冊具備至少一種方法的接口; 具體類將被忽略」。
而我本身習慣的作法是,在applicationContext-dao.xml中進行以下聲明,把MyBatis的相關映射接口註冊爲Bean:
<!--將指定的包中全部接口看成mapper來配置,以後能夠自動引入mapper類--> <mybatis:scan base-package="com.biguo.mapper"/>
因此須要確保把Mapper接口註冊爲Bean,不論用哪一種方式,都是能夠的,而同目錄下的xml文件是被自動加載。
第一種狀況的解決方案就是這樣。
2、Mapper接口文件和對應的XML在不一樣的目錄下
以下圖,我習慣的作法是在進行MyBatis逆向生成時,把Mapper接口放在src/main/java下,把對應的XML文件放到src/main/resources下,分開存放。
mapper接口是必定要註冊爲Bean的,上面提到的兩種方式均可以。
而後就是,告訴MyBatis去哪裏找到哪些映射SQL語句的XML文件,最最經常使用的就是在MyBatis 的核心配置文件中使用<mappers>標籤進行指定。官方文檔也說得很清楚:MyBatsi官方文檔 。
官方文檔裏寫了有四種方式來指定xml映射文件的位置:類路徑相對資源引用(resource),徹底限定的url引用(包括file:/// URL),類名或包名,下面分別舉個例子:
<mappers> <mapper resource="org/mybatis/builder/AuthorMapper.xml"/> <mapper url="file:///var/mappers/AuthorMapper.xml"/> <mapper class="org.mybatis.builder.AuthorMapper"/> <package name="org.mybatis.builder"/> </mappers>
然而,根據這位朋友(Hern)的文章(參考出處),這四種指定方式有必定的限制:
一、當採用class、package方式時,映射文件(Mapper.xml)和接口必須命名相同,而且放在與接口同一目錄下。(儘可能不要採用這種方法)
二、當採用class方式時,沒有SQL映射文件,全部的SQL都是利用註解寫在接口上,這樣就能夠避免注意1的事情發生,提升維護性,不是很重要的SQL語句能夠採用註解的方式,這樣能夠提升開發速度,重要和複雜的接口、SQL建議仍是採用SQL映射文件的方式。(儘可能採用這種方法)
我什麼會搜到這位朋友的文章呢?由於我本身有個問題一直沒解決。
之前通常都是用resource指定xml文件的位置,不論有多少個xml文件,都在<mappers>裏一個個寫出來,由於我找不到能夠批量指定的方法(通配符什麼的試了,沒成功)(注意別忘了如今的背景是mapper接口和xml映射文件在不一樣的目錄下)。
Hern的文章提醒了我,能夠指定一個Package來批量加載XML映射文件,可是它們必須和mapper接口在同一目錄下。若是是這樣,那咱們又回到了上第一種狀況——必須解決掉IDEA下Maven工程默認不會對src/main/java的非.java文件的行爲。這樣作好像也不錯,也就是能夠不須要批量指定,只要配置了Maven節點,mapper接口同目錄下的xml映射文件就能自動加載了。
因此如今的問題就變成了:必須在XML文件與mapper接口在不一樣目錄下的狀況下找到批量加載XML映射文件的方法。
還真的找到了,StackOverflow(How to load mapper xml files with wildcard?)給了啓發。
方法就是在applicationContext-dao.xml註冊SqlSessionFactory的bean時,設置一個"mapperLocation"屬性(property),來告訴MyBatis那些XML映射文件的位置(可使用通配符),以下:
<!-- 讓spring管理sqlsessionfactory 使用mybatis和spring整合包中的 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 數據庫鏈接池 --> <property name="dataSource" ref="dataSource" /> <!-- 加載mybatis的全局配置文件 --> <property name="configLocation" value="classpath:mybatis/SqlMapConfig.xml" />
<!--批量指定mapper的xml文件的方法,此時xml無需與接口在同一個文件夾下--> <property name="mapperLocations" value="classpath*:mapper/*Mapper.xml"/> </bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.taotao.mapper" /> </bean>
也就是說,在同一個地方,建立了SqlSessionFactory的Bean,批量加載了XML映射文件,建立了全部mapper接口的Bean。這樣作,個人MyBatis核心配置文件就仍然能夠保持0配置。
而後我也查看了SqlSessionFactoryBean的官方文檔,這個類中的確有這麼一個方法:
void setMapperLocations(Resource[] mapperLocations)
Set locations of MyBatis mapper files that are going to be merged into the SqlSessionFactory configuration at runtime.This is an alternative to specifying "<sqlmapper>" entries in an MyBatis config file. This property being based on Spring's resource abstraction also allows for specifying resource patterns here: e.g. "classpath*:sqlmap/*-mapper.xml".
設置將在運行時合併到SqlSessionFactory配置中的MyBatis映射器文件的位置。 這是在MyBatis配置文件中指定「<sqlmapper>」條目的替代方法。 此屬性基於Spring的資源抽象,也容許在此指定資源模式,例如: "classpath*:sqlmap/*-mapper.xml"
還能再說什麼呢,Spring牛逼就完事了!!
這個應該是最佳解決方案了,ok,任務完成~