【Mybatis從0到1-007】深入MyBatis的配置文件

   根據前面學過的內容,可知,mybatis的持久化離不開sqlsessionfactory對象,這個對象是整個數據庫映射關係經過編譯後的內存鏡像,該對象的openSession()方法可以打開SqlSession對象。該對象由SqlSessionFactoryBuilder加載mybatis的配置文件產生。再來回顧下之前的代碼:

// mybatis配置文件
String resource = "SqlMapConfig.xml";
// 得到配置文件流
InputStream inputStream = Resources.getResourceAsStream(resource);
// 創建會話工廠,傳入mybatis的配置文件信息
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 通過工廠得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
   上面這段代碼的功能是根據配置文件SqlMapConfig.xml,創建SqlSessionFactory 對象,然後產生SqlSession對象,執行SQL語句。而mybatis的初始化就發生在第三句:

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
現在,來看下,這句代碼到底發生了什麼?

MyBatis初始化的基本過程:

   SqlSessionFactoryBuilder根據傳入的數據流生成Configuration對象,然後根據Configuration對象創建默認的SqlSessionFactory實例。

   初始化的基本過程如下所示:


簡述初始化的過程:

1.調用SqlSessionFactoryBuilder對象的build(inputStream)方法;

2.SqlSessionFactoryBuilder會根據輸入流inputStream等信息創建XMLConfiguration對象;

3.SqlSessionFactoryBuilder調用XMLConfiguration對象的parse()方法;

4.XMLConfiguration對象解析XML配置文件並返回Configuration對象;

5.SqlSessionFactoryBuilder根據Configuration對象創建一個DefaultSessionFactory對象;

6.SqlSessionFactoryBuilder返回DefaultSessionFactory對象給客戶端,供客戶端使用。

由此可見,SqlSessionFactory是根據mybatis的配置文件創建的。下面開始簡單介紹全局配置文件SQLMapConfig.xml

配置內容如下:
properties(屬性)
settings(全局配置參數)
typeAliases(類型別名)
typeHandlers(類型處理器)
objectFactory(對象工廠)
plugins(插件)
environments(環境集合屬性對象)
environment(環境子屬性對象)
transactionManager(事務管理)
dataSource(數據源)
mappers(映射器)

【1】properties(屬性

由xml文件內容可以發現,文件中存在很多硬編碼,現在我們的需求如下:

將數據庫連接參數單獨配置在db.properties中(原因:方便對參數進行統一管理,其它xml可以引用該db.properties),只需要在SqlMapConfig.xml中加載db.properties的屬性值。在SqlMapConfig.xml中就不需要對數據庫連接參數硬編碼。

下面,開始修改全局配置文件,創建文件db.properties(路徑:src\main\resources\db.properties),添加內容如下:

jdbc.driver =com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8
jdbc.username = root
jdbc.password = 123

修改SqlMapConfig.xml文件,如下:


修改完成後,可以將上一章【Mybatis從0到1-006】mybatis開發DAO之基於mapper代理的測試程序再次運行下,看是否還能正常運行,測試結果表明,配置正確。

總結:

MyBatis 將按照下面的順序來加載屬性:
在 properties 元素體內定義的屬性首先被讀取。 
然後會讀取properties 元素中resource或 url 加載的屬性,它會覆蓋已讀取的同名屬性。 
最後讀取parameterType傳遞的屬性,它會覆蓋已讀取的同名屬性。所以這裏可能就會存在一個問題:假如UserMapper.xml中的有一個statement的入參名爲name,

<select id="findUserByUsername" parameterType="java.lang.String" resultType="po.User">
    SELECT *FROM  user WHERE username LIKE '%${name}%'
</select>
而db.properties中也有一個參數名叫name。

name = root
jdbc.password = 123

那最終UserMapper.xml中的select會讀取到name=root,而不是用戶傳入的值。

建議:
不要在properties元素體內添加任何屬性值,只將屬性值定義在properties文件中。在properties文件中定義屬性名要有一定的特殊性,如:XXXXX.XXXXX.XXXX

【2】typeAliases(別名)

   在mapper.xml中,定義了很多的statement,statement需要parameterType指定輸入參數的類型、需要resultType指定輸出結果的映射類型。
   如果在指定類型時輸入類型全路徑,不方便進行開發,可以針對parameterType或resultType指定的類型定義一些別名,在mapper.xml中通過別名定義,方便開發。

   mybatis有一些默認的別名,這裏不再羅列,主要說一下自定義別名。類型別名是爲了java類型設置的一些短的名字,它只和xml配置有關,存在的意義僅在於用來減少類完全限定名的冗餘。

<typeAliases>
    <!--創建單個別名-->
    <typeAlias type="po.User" alias="user"></typeAlias>
</typeAliases>

這樣配置時,user可以使用在任何使用po.User的地方。

<select id ="findUserById" parameterType="int" resultType="user">
    SELECT *FROM user WHERE id=#{id}
</select>

除此外,還可以批量定義別名(常用), 指定一個包名,mybatis會在包下面掃描需要的java bean。

<typeAliases>
    <!--創建單個別名-->
    <!--<typeAlias type="po.User" alias="usersong"></typeAlias>-->
    <!--批量別名-->
    <package name="po"/>
</typeAliases>
每一個在包po中的java bean,在沒有註解的情況下,會使用Bean的首字母小寫的非限定類名來作爲它的別名。比如po.User的別名爲user;若有註解的話,則它的別名爲其註解值。

@Alias("user")
public class User {
	…………
}

【3】mapper映射器

   mybatis需要開發者自己書寫SQL語句,mapper映射器正是告訴MyBatis到哪裏去找映射文件(在SqlMapConfig.xml文件中修改),進而找到這些SQL語句。實際開發中,可以使用相對於類路徑的資源引用或完全限定資源定位符(包括file:///的URL),以及類名和包名等。例如:

3.1 通過resource加載單個映射文件(我們之前開發的都是基於此加載方式)

<!-- 加載 映射文件 -->
<mappers>
    <!--<mapper resource="sqlmap/User.xml"/>-->
    <mapper resource="mapper/UserMapper.xml"/>
</mappers>

3.2 通過本地文件

<mappers>
    <mapper url="file:///C:/mapper/UserMapper.xml"/>
</mappers>

3.3 通過mapper接口加載單個映射文件(使用這種方法的前提是:使用的是mapper代理方法

這種方法開發還需要遵循一些規範:需要將mapper接口類名和mapper.xml映射文件名稱保持一致,且在同一個目錄中!!!

<!-- 加載 映射文件 -->
<mappers>
    <!--<mapper resource="sqlmap/User.xml"/>-->
    <!--通過resource加載單個映射文件-->
    <!--<mapper resource="mapper/UserMapper.xml"/>-->
    <!--加載本地文件-->
    <!--<mapper url="file:///C:/mapper/UserMapper.xml"/>-->
    <!-- 通過mapper接口加載單個 映射文件
    遵循一些規範:需要將mapper接口類名和mapper.xml映射文件名稱保持一致,且在一個目錄中
    上邊規範的前提是:使用的是mapper代理方法 -->
    <mapper class="mapper.UserMapper"/>
</mappers>

 通過idea開發,在測試mapper接口過程中,出現了一個問題,就是當把resources\mapper文件夾下的UserMapper.xml文件移動到src\main\java\mapper後,兩個文件雖在同一目錄了,但是運行測試程序,報錯。


出現這個問題的原因是idea中我將mapper類型默認是source類型,而xml文件在發佈時不會編譯,同時也不會發布到target中(所以在發佈之後target目錄中並沒有xml,路徑:target\classes\mapper\),導致項目運行時找不到mapper.xml文件。

然而,當只遵循部分規範(需要將mapper接口類名和mapper.xml映射文件名稱保持一致),不遵循且在同一個目錄中!!!,運行程序,居然沒有報錯,真的很奇怪!!

…………………………………………………………………………………………………………………………………………………………………………………………………………………………………………

對於這個問題,網友解釋如下:

解決方案:

    將UserMapper.xml文件提取到指定文件夾mapper中,設置mapper文件夾類型爲resources,在SqlMapConfig.xml配置文件中添加圖片中框選的代碼對mapper文件進行掃描,問題解決。【這個問題在學習完Spring與mybatis結合之後將更容易解決。】


3.4 批量加載mapper(推薦使用)

批量加載與3.3所說的加載單個映射文件原理相似,只不過是一個用了class,一個用了package,這裏先貼出代碼。

<!-- 批量加載mapper
指定mapper接口的包名,mybatis自動掃描包下邊所有mapper接口進行加載
遵循一些規範:需要將mapper接口類名和mapper.xml映射文件名稱保持一致,且在一個目錄 中
上邊規範的前提是:使用的是mapper代理方法
 -->
<package name="mapper"/>

以上就是mybatis的配置文件的最主要內容。接下來章節將介紹輸入映射、輸出映射。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章