通過上一章的學(xué)習(xí),大家對(duì) MyBatis 框架的使用已經(jīng)有了一個(gè)初步的了解,但是要想熟練地使用 MyBatis 框架進(jìn)行實(shí)際開發(fā),只會(huì)簡(jiǎn)單的配置是不行的,我們還需要對(duì)框架中的核心對(duì)象, 以及映射文件和配置文件有更加深入的了解。 接下來,本章將對(duì)這些內(nèi)容進(jìn)行詳細(xì)的講解。
MyBatis 的核心對(duì)象
在使用 MyBatis 框架時(shí),主要涉及兩個(gè)核心對(duì)象: SqlSessionFactory 和 SqlSession ,它們 在 MyBatis 框架中起著至關(guān)重要的作用。 本節(jié)將對(duì)這兩個(gè)對(duì)象進(jìn)行詳細(xì)講解。
- SqlSessionFactory
SqlSessionFactory 是 MyBatis 框架中十分重要的對(duì)象,它是單個(gè)數(shù)據(jù)庫映射關(guān)系經(jīng)過編譯后的內(nèi)存鏡像,其主要作用是創(chuàng)建 SqlSession。SqlSessionFactory 對(duì)象的實(shí)例可以通過 SqlSessionFactoryBuilder 對(duì)象來構(gòu)建,而 SqlSessionFactoryBuilder 則可以通過 XML 配置文件或一個(gè)預(yù)先定義好的 Configuration 實(shí)例構(gòu)建出 SqlSessionFactory 的實(shí)例。 我們所講解的就是通過 XML 配置文件構(gòu)建出的 SqlSessionFactory 實(shí)例,其實(shí)現(xiàn)代碼如下:
// 讀取配置文件 InputStream inputStream = Resources.getResourceAsStream("配置文件位置"); // 根據(jù)配置文件構(gòu)建 Sq1SessionFactory SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);SqISessionFactory 對(duì)象是線程安全的,它一旦被創(chuàng)建,在整個(gè)應(yīng)用執(zhí)行期間都會(huì)存在。 如果我們多次地創(chuàng)建同一個(gè)數(shù)據(jù)庫的 SqlSessionFactory,那么此數(shù)據(jù)庫的資源將很容易被耗盡。 為了解決此問題,通常每一個(gè)數(shù)據(jù)庫都會(huì)只對(duì)應(yīng)一個(gè) SqlSessionFactory,所以在構(gòu)建 SqlSessionFactory 實(shí)例時(shí),建議使用單列模式。
- SqlSession
SqlSession 是 MyBatis 框架中另一個(gè)重要的對(duì)象,它是應(yīng)用程序與持久層之間執(zhí)行交互操作的一個(gè)單線程對(duì)象,其主要作用是執(zhí)行持久化操作。 SqlSession 對(duì)象包含了數(shù)據(jù)庫中所有執(zhí) 行 SQL 操作的方法,由于其底層封裝了 JDBC 連接,所以可以直接使用其實(shí)例來執(zhí)行己映射的 SQL 語句。
每一個(gè)線程都應(yīng)該有一個(gè)自己的 SqlSession 實(shí)例,并且該實(shí)例是不能被共享的。 同時(shí), SqlSession 實(shí)例也是線程不安全的,因此其使用范圍最好在一次請(qǐng)求或一個(gè)方法中,絕不能將其放在一個(gè)類的靜態(tài)字段、實(shí)例字段或任何類型的管理范圍(如 Servlet 的 HttpSession )中使用。 使用完 SqlSession 對(duì)象之后,要及時(shí)地關(guān)閉它,通??梢詫⑵浞旁?finally 塊中關(guān)閉,代碼如下所示。SqlSession sqlSession = sqlSessionFactory.openSession(); try{ //此處執(zhí)行持久化操作 }finally{ sqlSession.close(); }SqlSession 對(duì)象中包含了很多方法,其常用方法如下所示。
<T> T selectOne ( String statement ); 查詢方法。 參數(shù) statement 是在配置文件中定義的<select>元素的 id。 使用該方法后,會(huì)返 回執(zhí)行 SOL 語句查詢結(jié)果的一條泛型對(duì)象。
<T> T selectOne ( String statement, Object parameter ); 查詢方法。 參數(shù) statement 是在配置文件中定義的<selecb元素的 id , parameter 是查詢所 需的參數(shù)。 使用該方法后,會(huì)返回執(zhí)行 SOL 語句查詢結(jié)果的一條泛型對(duì)象。
<E> List<E> selectList ( String statement ); 查詢方法。 參數(shù) statement 是在配置文件中定義的<select>元素的 id。 使用該方法后,會(huì)返 回執(zhí)行 SOL 語句查詢結(jié)果的泛型對(duì)象的集合。
<E> List<E> selectList ( String statement, Object parameter ); 查詢方法。 參數(shù) statement 是在配置文件中定義的<selecb元素的 id , parameter 是查詢所 需的參數(shù)。 使用該方法后,會(huì)返回執(zhí)行 SOL 語句查詢結(jié)果的泛型對(duì)象的集合。
<E> List<E> selectList ( String statement, Object parameter, RowBounds rowBounds ); 查詢方法。 參數(shù) statement 是在配置文件中定義的<select>元素的 id , parameter 是查詢所 需的參數(shù), rowBounds 是用于分頁的參數(shù)對(duì)象。 使用該方法后,會(huì)返回執(zhí)行 SOL 語句查詢結(jié)果 的泛型對(duì)象的集合。
void select ( String statement, Object parameter, ResultHandler handler ); 查詢方法。 參數(shù) statement 是在配置文件中定義的<selecb元素的 id , >- parameter 是查詢所 需的參數(shù), ResultHandler 對(duì)象用于處理查詢返回的復(fù)雜結(jié)果集,通常用于多表查詢。
int insert ( String statement ); 插入方法。 參數(shù) statement 是在配置文件中定義的<inserb元素的 id。 使用該方法后,會(huì)返 回執(zhí)行 SOL 語句所影響的行數(shù)。
int insert ( String statement, Object parameter ); 插入方法。 參數(shù) statement 是在配置文件中定義的<inserb元素的 id , parameter 是插入所 需的參數(shù)。 使用該方法后,會(huì)返回執(zhí)行 SOL 語句所影響的行數(shù)。
int update ( String statement ); 更新方法。 參數(shù) statement 是在配置文件中定義的<update>元素的 id。 使用該方法后,會(huì) 返回執(zhí)行 SOL 語句所影響的行數(shù)。
int update ( String statement, Object parameter ); 更新方法。 參數(shù) statement 是在配置文件中定義的<update>元素的 id , parameter 是更新 所需的參數(shù)。 使用該方法后,會(huì)返回執(zhí)行 SOL 語句所影響的行數(shù)。
int delete ( String statement ); 刪除方法。 參數(shù) statement 是在配置文件中定義的<delete>元素的 id。 使用該方法后,會(huì)返 回執(zhí)行 SOL 語句所影響的行數(shù)。int delete ( String statement, Object parameter ); 刪除方法。 參數(shù) statement 是在配置文件中定義的<delete>元素的 id , parameter 是刪除所 需的參數(shù)。 使用該方法后,會(huì)返回執(zhí)行 SOL 語句所影響的行數(shù)。
void commit(); 提交事務(wù)的方法。
void rollback(); 回滾事務(wù)的方法。
void close(); 關(guān)閉 SqlSession 對(duì)象。
<T> T getMappe r(Class<T> type) ;該方法會(huì)返回 Mapper 接口的代理對(duì)象,該對(duì)象關(guān)聯(lián)了 SqlSession 對(duì)象,開發(fā)人員可以使 用該對(duì)象直接調(diào)用方法操作數(shù)據(jù)庫。 參數(shù) type 是 Mapper 的接口類型。 MyBatis 官方推薦通過 Mapper 對(duì)象訪問 MyBatis。
Connection getConnection(); 獲取 JDBC 數(shù)據(jù)庫連接對(duì)象的方法。
多學(xué)一招: 使用工具類創(chuàng)建SqlSession
在上一節(jié)的入門案例中,每個(gè)方法執(zhí)行時(shí)都需要讀取配直文件,并根據(jù)配直文件的信息構(gòu)建 SqlSessionFactory 對(duì)象,然后創(chuàng)建 SqlSession 對(duì)象,這導(dǎo)致了大量的重復(fù)代碼。為了簡(jiǎn)化開發(fā), 我們可以將上述重復(fù)代碼封裝到一個(gè)工具類中,然后通過工具類來創(chuàng)建 SqlSession, 文件如下所示。package com.neuedu.utils; import java.io.Reader; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; /** * 工具類 */ public class MybatisUtils { private static SqlSessionFactory sqlSessionFactory = null; //初始化SqlSessionFactory對(duì)象 static{ try{ //使用MyBatis提供的Resouces類加載MyBatis的配置文件 Reader reader = Resources.getResourceAsReader("mybatis-config.xml"); //構(gòu)建SqlSessionFactory工廠 sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); }catch (Exception e) { e.printStackTrace(); } } //獲取 SqlSession對(duì)象的靜態(tài)方法 public static SqlSession getSession(){ return sqlSessionFactory.openSession(); } }這樣,我們?cè)谑褂脮r(shí)就只創(chuàng)建了一個(gè) SqlSessionFactory 對(duì)象,并且可以通過工具類的 getSession() 方法,來獲取 SqlSession 對(duì)象。
配置文件
MyBatis 的核心配置文件中,包含了很多影響 MyBatis 行為的重要信息。 這些信息通常在一 個(gè)項(xiàng)目中只會(huì)在一個(gè)配置文件中編寫,并且編寫后也不會(huì)輕易改動(dòng)。 雖然在實(shí)際項(xiàng)目中需要開發(fā) 人員編寫或者修改的配置文件不多,但是熟悉配置文件中各個(gè)元素的功能還是十分重要的。 接下來的幾個(gè)小節(jié)中,將對(duì) MyBatis 配置文件中的元素進(jìn)行詳細(xì)的講解。
- 主要元素
在 MyBatis 框架的核心配置文件中, <configuration>元素是配置文件的根元素,其他元素 都要在 <configuration>元素內(nèi)配置。 在上一章的入門案例中,我們?cè)谂渲梦募?nèi)只使用了 <environments>和<mapper>等幾個(gè)元素,但在實(shí)際開發(fā)時(shí),通常還會(huì)對(duì)其他一些元素進(jìn)行配置。
MyBatis 配置文件中的主要元素如圖所示。
從圖中可以看到,在 MyBatis 的配置文件中包含了多個(gè)元素,這些元素在配置文件中分別發(fā)揮著不同的作用。 開發(fā)人員所需要熟悉的就是圖中<configuration>元素各個(gè)子元素的配置。
注意:<configuration>的子元素必須按照上圖中由上到下的順序進(jìn)行配置,否則 MyBatis 在解析 XML 配置文件的時(shí)候會(huì)報(bào)錯(cuò)。
- <properties>元素
<properties>是一個(gè)配置屬性的元素,該元素通常用于將內(nèi)部的配置外在化,即通過外部的配置來動(dòng)態(tài)地替換內(nèi)部定義的屬性。 例如,數(shù)據(jù)庫的連接等屬性,就可以通過典型的 Java 屬性 文件中的配置來替換,具體方式如下。
( 1 )在項(xiàng)目的 src 目錄下,添加一個(gè)全名為 db.properties 的配置文件,編輯后的代碼如下所示。jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/mybatis jdbc.username=root jdbc.password=root( 2 )在 MyBatis 配置文件 mybatis-config.xml 中配置<properties... />屬'性,具體如下。
<properties resource="db.properties"/>( 3 )修改配置文件中數(shù)據(jù)庫連接的信息,具體如下。
<dataSource type="POOLED"> <!-- 數(shù)據(jù)庫驅(qū)動(dòng) --> <property name="driver" value="${jdbc.driver}" /> <!-- 鏈接數(shù)據(jù)庫的url --> <property name="url" value="${jdbc.url}" /> <!-- 連接數(shù)據(jù)庫的用戶名 --> <property name="username" value="${jdbc.username}" /> <!-- 連接數(shù)據(jù)庫的密碼 --> <property name="password" value="${jdbc.password}" /> </dataSource>完成上述配置后, dataSource 中連接數(shù)據(jù)庫的 4 個(gè)屬性( driver、url、username 和 password) 值將會(huì)由 db.properties 文件中對(duì)應(yīng)的值來動(dòng)態(tài)替換。 這樣就為配置提供了諸多靈活的選擇。
除了可以像上述通過外部配置文件來定義屬性值外,還可以通過配置<properties>元素的子元素<property> ,以及通過方法參數(shù)傳遞的方式來獲取屬性值。 由于使用 properties 配置文件來配置屬性值可以方便地在多個(gè)配置文件中使用這些屬性值,并且方便曰后的維護(hù)和修改,所以在實(shí)際開發(fā)中,使用 properties 配置文件來配置屬性值是最常用的方式。 在這里我所使用的就是此種方式,關(guān)于其他兩種方式,有興趣大家可自行查找資料學(xué)習(xí)。
- <settings>元素
<settings>元素主要用于改變 MyBatis 運(yùn)行時(shí)的行為,例如開啟二級(jí)緩存、開啟延遲加載等。 雖然不配置<settings>元素,也可以正常運(yùn)行 MyBatis,但是熟悉<settings>的配置內(nèi)容以及它們的作用還是十分必要的。
<settings>元素中的常見配置及其描述如表所示。
設(shè)置參數(shù) 描述 有效值 默認(rèn)值 cacheEnabled 該配置影響所茍映射器中配置的緩存全局開關(guān) true 或false false lazyLoadingEnabled 延遲加載的全局開關(guān)。開啟時(shí),所有關(guān)聯(lián)對(duì)象都會(huì)延遲 加載。特定關(guān)聯(lián)關(guān)系中可以通過設(shè)置 fetchType 屬性覆蓋該項(xiàng)的開關(guān)狀態(tài) true 或false true aggressiveLazyLoading 關(guān)聯(lián)對(duì)象屬性的延遲加載開關(guān)。當(dāng)啟用時(shí),對(duì)任意延遲屬性的調(diào)用會(huì)使帶有延遲加載屬性的對(duì)象完整加載;反之,每種屬性都會(huì)投需加載 true 或false true multipleResultSetsEnabled 是否允許單一語句返回多結(jié)果集(需要兼容驅(qū)動(dòng)) true 或false true useColumnLabel 使用列標(biāo)簽代替列名 。不同的驅(qū)動(dòng)在這方面離不同的表現(xiàn)。 具體可參考驅(qū)動(dòng)文檔或通過測(cè)試兩種模式來觀察所用驅(qū)動(dòng)的行為 true 或false true useGeneratedKeys 允許 JDBC 支持自動(dòng)生成主鍵,需要驅(qū)動(dòng)兼容。如果設(shè)置為 true,則這個(gè)設(shè)置強(qiáng)制使用自動(dòng)生成主鍵,盡管一些驅(qū)動(dòng)不兼容但仍可正常工作 true 或false false autoMappingBehavior 指定 MyBatis 應(yīng)如何自動(dòng)映射列到字段或?qū)傩浴?NONE表示取消自動(dòng)映射; PARTIAL 只會(huì)自動(dòng)映射沒離定義嵌套結(jié)果集映射的結(jié)果集; FULL 會(huì)自動(dòng)映射任意復(fù)雜 的結(jié)果集(無論是否嵌套) NONE、PARTIAL、FULL PARTIAL defaultExecutorType 配置默認(rèn)的執(zhí)行器。 SIMPLE 就是普通的執(zhí)行器;執(zhí)行器會(huì)重用預(yù)處理語句 (prepared statements) ; BATCH 執(zhí)行器將重用語句并執(zhí)行批量更新 SIMPLE、REUSE、 BATCH SIMPLE defaultStatementTimeout 設(shè)置超時(shí)時(shí)間, 它決定驅(qū)動(dòng)等待數(shù)據(jù)庫響應(yīng)的秒數(shù)。 當(dāng)沒有設(shè)置的時(shí)候,它取的就是驅(qū)動(dòng)的默認(rèn)時(shí)間 任何正整數(shù) 沒有設(shè)置 mapUnderscoreToCamelCase 是否開啟自動(dòng)~8峰命名規(guī)則( camel case )映射 true 或false false jdbcTypeForNull 當(dāng)沒有為參數(shù)提供特定的 JDBC 類型時(shí),為空值指定JDBC 類型。 某些驅(qū)動(dòng)需要指定列的 JDBC 類型,多數(shù)情況直接用一般類型即可,比如 NULL、 VARCHAR 或 OTHER NULL、VARCHAR、 OTHER OTHER 表中介紹了 <settings>元素中的常見配置,這些配置在配置文件中的使用方式如下。
<!-- 設(shè)置 --> <settings> <setting name= "cacheEnabled" value="true" /> <setting name= "lazyLoadingEnabled" value="true" /> <setting name= "multipleResultSetsEnabled" value="true" /> <setting name= "useColumnLabel" value="true" /> <setting name= "useGeneratedKeys" value="true" /> <setting name= "autoMappingBehavior" value="true" /> ... </settings>上面所介紹的配置內(nèi)容大多數(shù)都不需要開發(fā)人員去配置它,通常在需要時(shí)只配置少數(shù)幾項(xiàng)即可。 這里大家只需要了解這些可設(shè)置的參數(shù)值及其含義即可。
- <typeAliases>元素
<typeAliases>元素用于為配置文件中的 Java 類型設(shè)置一個(gè)簡(jiǎn)短的名字,即設(shè)置別名。 別名的設(shè)置與 XML 配置相關(guān),其使用的意義在于減少全限定類名的冗余。 使用<typeAliases>元素配置別名的方法如下。
<!-- 定義別名 --> <typeAliases> <typeAlias alias="user" type="com.neuedu.po.User"/> </typeAliases>上述示例中, <typeAliases>元素的子元素<typeAlias>中的 type 屬性用于指定需要被定義別名的類的全限定名;alias 屬性的屬性值 user 就是自定義的別名,它可以代替 com.neuedu. po.User 使用在 MyBatis 文件的任何位置。 如果省略 alias 屬性, MyBatis 會(huì)默認(rèn)將類名首字母小寫后的名稱作為別名。
當(dāng) POJO 類過多時(shí),還可以通過自動(dòng)掃描包的形式自定義別名,具體示例如下。<!-- 使用自動(dòng)掃描包來定義別名 --> <typeAliases> <package name="com.neuedu.po"/> </typeAliases>上述示例中, <typeAliases>元素的子元素<package>中的 name 屬性用于指定要被定義別名的包, MyBatis 會(huì)將所有 com.neuedu.po 包中的 POJO 類以首字母小寫的非限定類名來作為它的別名,比如 com.neuedu.po.User 的別名為 user , com.neuedu.po.Customer 的別名為 customer 等。
需要注意的是,上述方式的別名只適用于沒有使用注解的情況。 如果在程序中使用了注解, 則別名為其注解的值,具體如下。@Alias(value= "user") public class User { //User 的屬性和方法 ... }除了可以使用<typeAliases>元素自定義別名外, MyBatis 框架還默認(rèn)為許多常見的 Java 類型(如數(shù)值、字符串、曰期和集合等)提供了相應(yīng)的類型別名,如表所示。
別名 映射的類型 _byte byte _Iong long _short short _int int _integer int _double double _float float _boolean boolean string String byte Byte long Long short Short int Integer integer Integer double Double float Float boolean Boolean date Date decimal BigDecimal bigdecimal BigDecimal object Object map Map hashmap HashMap list List arraylist Arraylist collection Collection iterator Iterator 表中所列舉的別名可以在 MyBatis 中直接使用,但由于別名不區(qū)分大小寫,所以在使用時(shí)要注意重復(fù)定義的覆蓋問題。
- <typeHandler>元素
MyBatis 在預(yù)處理語句( PreparedStatement )中設(shè)置一個(gè)參數(shù)或者從結(jié)果集( ResultSet ) 中取出一個(gè)值時(shí),都會(huì)用其框架內(nèi)部注冊(cè)了的 typeHandler (類型處理器)進(jìn)行相關(guān)處理。 typeHandler 的作用就是將預(yù)處理語句中傳入的參數(shù)從 javaType ( Java 類型)轉(zhuǎn)換為 jdbcType ( JDBC 類型),或者從數(shù)據(jù)庫取出結(jié)果時(shí)將 jdbcType 轉(zhuǎn)換為 javaType。
為了方便轉(zhuǎn)換, MyBatis 框架提供了一些默認(rèn)的類型處理器,其常用的類型處理器如表所示。
類型處理器 Java類型 JDBC類型 BooleanTypeHandler java.lang.Boolean, boolean 數(shù)據(jù)庫兼容的 BOOLEAN ByteTypeHandler java.lang.Byte, byte 數(shù)據(jù)庫兼容的 NUMERIC 或 BYTE ShortTypeHandler java.lang.Short, short 數(shù)j居庫兼容的 NUMERIC 或 SHORT INTEGER IntegerTypeHandler java.lang.lnteger, int 數(shù)據(jù)庫兼容的 NUMERIC 或 INTEGER LongTypeHandler java.lang.Long, long 數(shù)據(jù)庫兼容的 NUMERIC 或 LONG INTEGE FloatTypeHandler java.lang.Float, float 數(shù)據(jù)庫兼容的 NUMERIC 或 FLOAT Double TypeHandler java.lang.Double, double 數(shù)據(jù)庫兼容的 NUMERIC 或 DOUBLE BigDecimalTypeHandler java.math.BigDecimal 數(shù)據(jù)庫兼容的 NUMERIC 或 DECIMAL StringTypeHandler java.lang.String CHAR, VARCHAR Clob TypeHandler java.lang.String CLOB , LONGVARCHAR ByteArrayTypeHandler byte[] 數(shù)據(jù)庫兼容的字節(jié)流類型 BlobTypeHandler byte[] BLOB , LONGVARBINARY DateTypeHandler java.util.Date TIMESTAMP SqlTimestampTypeHandler java.sql.Timestamp TIMESTAMP SqlDateTypeHandler java.sql.Date DATE SqlTimeTypeHandler java.sql.Time TIME 當(dāng) MyBatis 框架所提供的這些類型處理器不能夠滿足需求時(shí),還可以通過自定義的方式對(duì)類型處理器進(jìn)行擴(kuò)展(自定義類型處理器可以通過實(shí)現(xiàn) TypeHandler 接口或者繼承 BaseTypeHandle 類來定義 )。 <typeHandler>元素就是用于在配置文件中注冊(cè)自定義的類型處 理器的。 它的使用方式有兩種,具體如下。
- 注冊(cè)一個(gè)類的類型處理器
<typeHandlers> <!-- 以單個(gè)類的形式配置 --> <typeHandler handler="com.neuedu.type.CustomtypeHandler"/> </typeHandlers>上述代碼中,子元素<typeHandler>的 handler 屬性用于指定在程序中自定義的類型處理器類。
- 注冊(cè)一個(gè)包中所有的類型處理器
<typeHandlers> <!-- 注冊(cè)一個(gè)包中所有的 typeHandler,系統(tǒng)在啟動(dòng)時(shí)會(huì)自動(dòng)掃描包下的所有文件 --> <typeHandler handler="com.neuedu.type" /> </typeHandlers>上述代碼中,子元素<package>的 name 屬性用于指定類型處理器所在的包名,使用此種方式后,系統(tǒng)會(huì)在啟動(dòng)時(shí)自動(dòng)地掃描 com.neuedu.type 包下所有的文件,并把它們作為類型處理器。
- <objectFactory>元素
MyBatis 框架每次創(chuàng)建結(jié)果對(duì)象的新實(shí)例時(shí),都會(huì)使用一個(gè)對(duì)象工廠( ObjectFactory )的實(shí)例來完成。 MyBatis 中默認(rèn)的 ObjectFactory 的作用就是實(shí)例化目標(biāo)類,它既可以通過默認(rèn)構(gòu)造方法實(shí)例化,也可以在參數(shù)映射存在的時(shí)候通過參數(shù)構(gòu)造方法來實(shí)例化。
在通常情況下,我們使用默認(rèn)的 ObjectFactory 即可, MyBatis 中默認(rèn)的 ObjectFactory 是由 org.apache.ibatis.reflection.factory.DefaultObjectFactory 來提供服務(wù)的。 大部分場(chǎng)景下都不用配置和修改,但如果想覆蓋 ObjectFactory 的默認(rèn)行為,則可以通過自定義 ObjectFactory 來實(shí)現(xiàn),具體方式如下。
( 1 ) 自定義一個(gè)對(duì)象工廠。 自定義的對(duì)象工廠需要實(shí)現(xiàn) ObjectFactory 接口,或者繼承 DefauItObjectFactory 類。 由于 DefaultObjectFactory 類已經(jīng)實(shí)現(xiàn)了 ObjectFactory 接口,所以通過繼承 DefaultObjectFactory 類實(shí)現(xiàn)即可,示例代碼如下所示。//自定義工廠類 public class MyObjectFactory extends DefaultObjectFactory { private static final long serialVersionUID = -5548708841003212961L; public <T> T Create(Class<T> type){ return super.create(type); } public <T> T Create(Class<T> type,List<Class<?>> constructorArgTypes, List<Object> constructorArgs){ return super.create(type, constructorArgTypes, constructorArgs); } public void setProperties(Properties properties) { super.setProperties(properties) ; } public <T> boolean isCollection(Class<T> type) { return Collection.class.isAssignableFrom(type); } }( 2 ) 在配置文件中使用<objectFactory>元素配置自定義的 ObjectFactory ,如下所示。
<objectFactory type="com.neuedu.factory.MyObjectFactory"> <property name="name" value="MyObjectFactory"/> </objectFactory>由于自定義 ObjectFactory 在實(shí)際開發(fā)時(shí)不經(jīng)常使用,這里大家只需要了解即可。
- <plugins>元素
MyBatis 允許在已映射語句執(zhí)行過程中的某一點(diǎn)進(jìn)行攔截調(diào)用,這種攔截調(diào)用是通過插件來實(shí)現(xiàn)的。 <plugins>元素的作用就是配置用戶所開發(fā)的插件。 如果用戶想要進(jìn)行插件開發(fā),必須要先了解其內(nèi)部運(yùn)行原理,因?yàn)樵谠噲D修改或重寫已有方法的行為時(shí),很可能會(huì)破壞 MyBatis 原有的核心模塊。 關(guān)于插件的使用,在這里不做詳細(xì)講解, 大家只需了解<plugins>元素的作用即可, 有興趣的可以查找官方文檔等資料自行學(xué)習(xí)。
- <environments>元素
在配置文件中, <environments>元素用于對(duì)環(huán)境進(jìn)行配置。 MyBatis 的環(huán)境配置實(shí)際上就是數(shù)據(jù)源的配置,我們可以通過<environments>元素配置多種數(shù)據(jù)源,即配置多種數(shù)據(jù)庫。
使用<environments>元素進(jìn)行環(huán)境配置的示例如下。<environments default="development"> <environment id="development"> <!-- 使用JDBC的事務(wù)管理 --> <transactionManager type="JDBC" /> <!-- 數(shù)據(jù)庫連接池 --> <dataSource type="POOLED"> <!-- 數(shù)據(jù)庫驅(qū)動(dòng) --> <property name="driver" value="${jdbc.driver}" /> <!-- 鏈接數(shù)據(jù)庫的url --> <property name="url" value="${jdbc.url}" /> <!-- 連接數(shù)據(jù)庫的用戶名 --> <property name="username" value="${jdbc.username}" /> <!-- 連接數(shù)據(jù)庫的密碼 --> <property name="password" value="${jdbc.password}" /> </dataSource> </environment> ... </environments>在上述示例代碼中, <environments>元素是環(huán)境配置的根元素,它包含一個(gè) default 屬性, 該屬性用于指定默認(rèn)的環(huán)境 ID。 <environment>是<environments>元素的子元素,它可以定義多個(gè),其 id 屬性用于表示所定義環(huán)境的 ID 值。 在<environment>元素內(nèi),包含事務(wù)管理和數(shù)據(jù)源的配置信息,其中<transactionManager>元素用于配置事務(wù)管理,它的 type 屬性用于指定事 務(wù)管理的方式,即使用哪種事務(wù)管理器;<dataSource>元素用于配置數(shù)據(jù)源,它的 type 屬性用于指定使用哪種數(shù)據(jù)源。
在 MyBatis 中 , 可以配置兩種類型的事務(wù)管理器,分別是 JDBC 和 MANAGED。 關(guān)于這兩 個(gè)事務(wù)管理器的描述如下。
- JDBC : 此配置直接使用 了 JDBC 的提交和回滾設(shè)置 , 它依賴于從數(shù)據(jù)源得到的連接來管理事務(wù)的作用域。
- MANAGED: 此配置從來不提交或回滾一個(gè)連接,而是讓容器來管理事務(wù)的整個(gè)生命周期。 在默認(rèn)情況下 , 它會(huì)關(guān)閉連接, 但一些容器并不希望這樣, 為此可以將 closeConnection 屬性設(shè)置為 false 來阻止它默認(rèn)的關(guān)閉行為。
注意:如果項(xiàng)目 中使用的是 Spring+ MyBatis,則沒有必要在 MyBatis 中配置事務(wù)管理器,因?yàn)閷?shí)際開發(fā)中,會(huì)使用 Spring 自帶的管理器來實(shí)現(xiàn)事務(wù)管理。
對(duì)于數(shù)據(jù)源的配置, MyBatis 框架提供了 UNPOOLED、 POOLED 和 JNDI 三種數(shù)據(jù)源類型, 具體如下。
- UNPOOLED
配置此數(shù)據(jù)源類型后,在每次被請(qǐng)求時(shí)會(huì)打開和關(guān)閉連接。 它對(duì)沒有性能要求的簡(jiǎn)單應(yīng)用程序是一個(gè)很好的選擇。
UNPOOLED 類型的數(shù)據(jù)源需要配置 5 種屬性,如表所示。
屬性 說明 driver JDBC 驅(qū)動(dòng)的 Java 類的完全限定名 ( 并不是 JDBC 驅(qū)動(dòng)中可能包含的數(shù)據(jù)源類) url 數(shù)據(jù)庫的 URL 地址 username 登錄數(shù)據(jù)庫的用戶名 password 登錄數(shù)據(jù)庫的密碼 defaultTransactionlsolationLevel 默認(rèn)的連接事務(wù)隔離級(jí)別
- POOLED
此數(shù)據(jù)源利用"池"的概念將 JDBC 連接對(duì)象組織起來,避免了在創(chuàng)建新的連接實(shí)例時(shí)所需要初始化和認(rèn)證的時(shí)間。 這種方式使得并發(fā) Web 應(yīng)用可以快速地響應(yīng)請(qǐng)求,是當(dāng)前流行的處理方式(在這里我們使用的就是此種方式)。
配置此數(shù)據(jù)源類型時(shí),除了上表中的 5 種屬性外,還可以配置更多的屬性,如下表所示。
屬性 說明 poolMaximumActiveConnections 在任意時(shí)間可以存在的活動(dòng)(也就是正在使用)連接數(shù)量,默認(rèn)值 10 poolMaximumldleConnections 任意時(shí)間可能存在的空閑連接數(shù) poolMaximumCheckoutTime 在被強(qiáng)制返回之劇,池中連接被檢出( checked out )時(shí)間,默認(rèn)值 :20000 毫秒, 即 20 秒 poolTimeToWait 如果獲取連接花費(fèi)的時(shí)間較長(zhǎng),它會(huì)給連接池打印狀態(tài)日志并重新嘗試獲取一個(gè)連接(避免在誤配置的情況下一直處于無提示的失敗) ,默認(rèn)值, 20000 毫秒, 即 20 秒 poolPingQuery 發(fā)送到數(shù)據(jù)庫的偵測(cè)查詢,用于檢驗(yàn)連接是否處在正常工作秩序中。默認(rèn)是 "NO PING QUERY SET" ,這會(huì)導(dǎo)致多數(shù)數(shù)據(jù)庫驅(qū)動(dòng)失敗時(shí)帶有一定的錯(cuò)誤信息 poolPingEnabled 是否啟用偵測(cè)查詢。若開啟,必須使用一個(gè)可執(zhí)行的 SQL 語句設(shè)置 poolPingQuery 屬性(最好是一個(gè)非??斓?SQL) ,默認(rèn)值 false poolPingConnectionsNotUsedFor 配置 poolPingQuery 的使用頻度??梢员辉O(shè)置成匹配具體的數(shù)據(jù)庫連接超時(shí)時(shí)間,來避免不必要的偵測(cè),默認(rèn)值: 0( 表示所有連接每一時(shí)刻都被偵測(cè), 只有 poolPingEnabled 的屬性值為 true 時(shí)適用)
- JNDI
此數(shù)據(jù)源可以在 EJB 或應(yīng)用服務(wù)器等容器中使用。 容器可以集中或在外部配置數(shù)據(jù)源,然后放置一個(gè) JNDI 上下文的引用。
配置 JNDI 數(shù)據(jù)源時(shí),只需要配置兩個(gè)屬性,如下所示。
- initial_context
此屬性主要用于在 InitialContext 中尋找上下文(即 initiaIContext.lookup(initial_context) ) 。 該屬性為可選屬性,在忽略時(shí), data source 屬性會(huì)直接從 InitialContext 中尋找- data_source
此屬性表示引用數(shù)據(jù)源實(shí)例位置的上下文的路徑。如果提供了 initial_context 配置,那么程序會(huì)在真返回的上下文中進(jìn)行查找;如果沒有提供,則直接在 InitialContext 中查找
- <mappers>元素
在配置文件中, <mappers>元素用于指定 MyBatis 映射文件的位置,一般可以使用以下 4 種方法引入映射器文件, 具體如下所示。
- 使用提路徑引入
<mappers> <mapper resource="com/neuedu/mapper/UserMapper.xml"></mapper> </mappers>
- 使用本地文件路徑引入
<mappers> <mapper url="file:///D:/com/neuedu/mapper/UserMapper.xml"></mapper> </mappers>
- 使用接口類引入
<mappers> <mapper class="com.neuedu.mapper.UserMapper"/> </mappers>
- 使用包名引入
<mappers> <package name="com.neuedu.mapper"/> </mappers>上述 4 種引入方式非常簡(jiǎn)單 , 大家可以根據(jù)實(shí)際項(xiàng)目需要選取使用。
映射文件
映射文件是 MyBatis 框架中十分重要的文件, 可以說, MyBatis 框架的強(qiáng)大之處就體現(xiàn)在映射文件的編寫上。 接下來的幾個(gè)小節(jié)中,將對(duì) MyBatis 映射文件中的元素進(jìn)行詳細(xì)講解。
- 主要元素
在映射文件中, <mapper>元素是映射文件的根元素 , 其他元素都是它的子元素。 這些子元素及其作用如圖所示。
- <select>元素
<select>元素用于映射查詢語句,它可以幫助我們從數(shù)據(jù)庫中讀取出數(shù)據(jù),并組裝數(shù)據(jù)給業(yè)務(wù)開發(fā)人員。
使用<select>元素執(zhí)行查詢操作非常簡(jiǎn)單,其示例如下。<select id="findCustomerByld" parameterType="Integer" resultType="com.neuedu.po.Customer"> select * from t_customer where id = #{id} </select>上述語句中的唯一標(biāo)識(shí)為 findCustomerByld ,它接收一個(gè) Integer 類型的參數(shù),并返回一個(gè) Customer 類型的對(duì)象。
<select>元素中,除了上述示例代碼中的幾個(gè)屬性外,還有其他一些可以配置的屬性,如下表所示。
屬性 說明 id 表示命名空間中的唯一標(biāo)識(shí)符,常與命名空間組合起來使用。組合后如果不唯一, MyBatis 會(huì)拋出異常 parameterType 該屬性表示傳入 SQL 語句的參數(shù)類的全限定名或者別名。它是一個(gè)可選屬性,因?yàn)?MyBatis 可以通過 TypeHandler 推斷出具體傳入語句的參數(shù)。其默認(rèn)值是 unset (依賴于驅(qū)動(dòng)) resultType 從 SQL 語句中返回的類型的類的全限定名或者別名。如果是集合類型,那么返回的應(yīng)該是集 合可以包含的類型,而不是集合本身。返回時(shí)可以使用 resultType 或 resultMap 之一 resultMap 表示外部 resultMap 的命名引用。返回時(shí)可以使用 resultType 或 resultMap 之一 flushCache 表示在調(diào)用 SQL 語句之后,是否需要 MyBatis 清空之前查詢的本地緩存和二級(jí)緩存。其值為布爾類型( true或false) ,默認(rèn)值為 false。如果設(shè)置為 true,則任何時(shí)候只要 SQL 語句被調(diào)用,都會(huì)清空本地緩存和二級(jí)緩存 useCache 用于控制二級(jí)緩存的開啟相關(guān)閉。其值為布爾類型( true或false) ,默認(rèn)值為 true ,表示將查 詢結(jié)果存入二級(jí)緩存中 timeout 用于設(shè)置超時(shí)參數(shù),單位為秒。超時(shí)時(shí)將拋出異常 fetchSize 獲取記錄的總條數(shù)設(shè)定,真默認(rèn)值是 unset (依賴于驅(qū)動(dòng)) statementType 用于設(shè)置 MyBatis 使用哪個(gè) JDBC 的 Statement 工作,真值為 STATEMENT、 PREPARED (默認(rèn)值)或 CALLABLE ,分別對(duì)應(yīng) JDBC 中的 Statement 、 PreparedStatement 和 CallableStatement resultSetType 表示結(jié)果集的類型,其值可設(shè)置為 FORWARD_ONLY 、 SCROLL_SENSITIVE 或 SCROLL_INSENSITIVE ,它的默認(rèn)值是 unset (依賴于驅(qū)動(dòng))
- <insert>元素
<insert>元素用于映射插入語句,在執(zhí)行完元素中定義的 SQL 語句后,會(huì)返回一個(gè)表示插入記錄數(shù)的整數(shù)。
<insert>元素的配置示例如下。<insert id="addCustomer" parameterType="com.neuedu.po.Customer" flushCache="true" statementType="PREPARED" keyProperty="" keyColumn="" useGeneratedKeys="" timeout="20">從上述示例代碼中可以看出 , <ínsert>元素的屬性與<select>元素的屬性大部分相同 , 但還包含了 3 個(gè)特有屬性,這 3 個(gè)屬性的描述如表所示。
屬性 說明 keyProperty (僅對(duì) insert和 update 有用)此屬性的作用是將插入或更新操作時(shí)的返回值賦值給 PO 類的某個(gè)屬性,通常會(huì)設(shè)置為主鍵對(duì)應(yīng)的屬性。 如果需要設(shè)置聯(lián)合主鍵,可以在多個(gè)值之間用逗號(hào)隔開 keyColumn (僅對(duì) insert和 update 有用)此屬性用于設(shè)置第幾列是主鍵,當(dāng)主鍵列不是表中的第一列時(shí)需要設(shè)置。在需要主鍵聯(lián)合時(shí),值可以用逗號(hào)隔開 useGeneratedKeys (僅對(duì) insert和 update 有用)此屬性會(huì)使 MyBatis 使用 JDBC 的 getGeneratedKeys() 方法來獲取由數(shù)據(jù)庫內(nèi)部生產(chǎn)的主鍵,如 MySQL 和 SQL Server等自動(dòng)遞增的字段,其默認(rèn)值為 false 執(zhí)行插入操作后,很多時(shí)候我們會(huì)需要返回插入成功的數(shù)據(jù)生成的主鍵值,此時(shí)就可以通過上面所講解的 3 個(gè)屬性來實(shí)現(xiàn)。
如果使用的數(shù)據(jù)庫支持主鍵自動(dòng)增長(zhǎng)(如 MySQL ),那么可以通過 keyProperty 屬性指定 PO 類的某個(gè)屬性接收主鍵返回值 ( 通常會(huì)設(shè)置到 id 屬性上 ),然后將 useGeneratedKeys 的屬性值設(shè)置為 true , 其使用示例如下。<insert id="addCustomer" parameterType="com.neuedu.po.Customer" keyProperty="id" useGeneratedKeys="true"> insert into t_customer(username,jobs,phone) values(#{username},#{jobs},#{phone}) </insert>使用上述配置執(zhí)行插入后,會(huì)返回插入成功的行數(shù),以及插入行的主鍵值。 為了驗(yàn)證此配置, 可以通過如下代碼測(cè)試。
@Test public void addCustomerTest(){ SqlSession sqlSession = MybatisUtils.getSession(); System.out.println(sqlSession); Customer customer = new Customer(); customer.setUsername("rose1"); customer.setJobs("student1"); customer.setPhone("13300007777"); int rows = sqlSession.insert("com.neuedu.mapper.CustomerMapper.addCustomer",customer); //輸出插入數(shù)據(jù)的主鍵 id值 System.out.println(customer.getId()); if(rows > 0){ System.out.println("您成功插入了"+rows+"條數(shù)據(jù)!"); }else{ System.out.println("執(zhí)行插入數(shù)據(jù)失?。。。?); } sqlSession.commit(); sqlSession.close(); }執(zhí)行程序后,控制臺(tái)的輸出結(jié)果如圖所示。
如果使用的數(shù)據(jù)庫不支持主鍵自動(dòng)增長(zhǎng)(如 Oracle ),或者支持增長(zhǎng)的數(shù)據(jù)庫取消了主鍵自增的規(guī)則時(shí),也可以使用 MyBatis 提供的另一種方式來自定義生成主鍵,具體配置示例如下。
<insert id="insertCustomer" parameterType="com.neuedu.po.Customer"> <selectKey keyProperty="id" resultType="Integer"> select if(max(id) is null,1,max(id)+1) as newId from t_customer </selectKey> insert into t_customer(id,username,jobs,phone) values(#{id},#{username},#{jobs},#{phone}) </insert>在執(zhí)行上述示例代碼時(shí), <selectKey>元素會(huì)首先運(yùn)行,它會(huì)通過自定義的語句來設(shè)置數(shù)據(jù) 表中的主鍵(如果 t_customer 表中沒有記錄,則將 id 設(shè)置為 1 ,否則就將 id 的最大值加 1 ,來作為新的主鍵),然后再調(diào)用插入語句。
<selectKey>元素在使用時(shí)可以設(shè)置以下幾種屬性。<selectKey keyProperty="id" resultType="Integer" order="BEFORE" statementType="STATEMENT">在上述<selectKey>元素的幾個(gè)屬性中, keyProperty、 resultType 和 statementType 的作用與前面講解的相同,這里不重復(fù)介紹。 order 屬性可以被設(shè)置為 BEFORE 或 AFTER。 如果設(shè)置 為 BEFORE ,那么它會(huì)首先執(zhí)行<selectKey>元素中的配置來設(shè)置主鍵,然后執(zhí)行插入語句;如果設(shè)置為 AFTER ,那么它會(huì)先執(zhí)行插入語句,然后執(zhí)行<selectKey>元素中的配置內(nèi)容。
- <update>元慧和<delete>元素
<update>和<delete>元素的使用比較簡(jiǎn)單,它們的屬性配置也基本相同( <delete>元素中不包含上面提到的 3 個(gè)屬性),其常用屬性如下所示。
<update id="updateCustomer" parameterType="com.neuedu.po.Customer" flushCache="true" statementType="PREPARED" timeout="20"> <delete id="deleteCustomer" parameterType="Integer" flushCache="true" statementType="PREPARED" timeout="20">從上述配置代碼中可以看出, <update>和<delete>元素的屬性基本與<select>元素中的屬性一致。 與<insert>元素一樣, <update>和<delete>元素在執(zhí)行完之后,也會(huì)返回一個(gè)表示影響記錄條數(shù)的整數(shù),其使用示例如下。
<!-- 更新信息 --> <update id="updateCustomer"> update t_customer set username=#{username},jobs=#{jobs},phone=#{phone} where id=#{id} </update> <!-- 刪除信息 --> <delete id="deleteCustomer" parameterType="Integer"> delete from t_customer where id=#{id} </delete>
- <sql>元素
在一個(gè)映射文件中,通常需要定義多條 SQL 語句,這些 SQL 語句的組成可能有一部分是相 同的(如多條 select 語句中都查詢相同的 id、 username、 jobs 字段),如果每一個(gè) SQL 語句都重寫一遍相同的部分,勢(shì)必會(huì)增加代碼量,導(dǎo)致映射文件過于腕腫。 那么有沒有什么辦法將這些 SQL 語句中相同的組成部分抽取出來,然后在需要的地方引用呢?答案是肯定的,我們可以在映射文件中使用 MyBatis 所提供的<sql>元素來解決上述問題。
<sql>元素的作用就是定義可重用的 SQL 代碼片段,然后在其他語句中引用這一代碼片段。 例如,定義一個(gè)包含 id、 username、 jobs 和 phone 字段的代碼片段如下。<sql id="customerColumns">id,username,jobs,phone</sql>這一代碼片段可以包含在其他語句中使用,具體如下。
<select id="findCustomerByld" parameterType="Integer" resultType="com.neuedu.po.Customer"> select <include refid="customerColumns" /> from t_customer where id = #{id} </select>在上述代碼中,使用<include>元素的 refid 屬性引用了自定義的代碼片段, refid 的屬性值為自定義代碼片段的 id。
上面示例只是一個(gè)簡(jiǎn)單的引用查詢。 在實(shí)際開發(fā)中,可以更加靈活地定義 SOL 片段,其示例如下。<!-- 定義表的前綴名 --> <sql id="tablename"> ${prefix}customer </sql> <sql id="someinclude"> from <include refid="${include_target}" /> </sql> <!--定義查詢列--> <sql id="customarColumns"> id,username,jobs,phone </sql> <!-- 根據(jù)id獲取客戶信息 --> <select id="findCustomerByld" parameterType="Integer" resultType="com.neuedu.po.Customer"> select <include refid="customarColumns" /> <include refid="someinclude"> <property name="prefix" value="t_"/> <property name="include_target" value="tablename"/> </include> where id = #{id} </select>上述代碼中,定義了 3 個(gè)代碼片段,分別為表的前綴名、要查詢的表和需要查詢的列。前兩個(gè)代碼片段中,分別獲取了 <include>子元素<property> 中的值,其中第 1 個(gè)代碼片段中的 "${prefix) "會(huì)獲取 name 為 prefix 的值 "t_" ,獲取后所組成的表名為 "t_customer" ; 而第 2 個(gè)代碼片段中的 "${include_target)"會(huì)獲取 name 為 include_target 的值 "tablename" ,由于 tablename 為第 1 個(gè) SOL 片段的 id 值,所以最后要查詢的表為 "t_customer"。所有的 SOL 片段在程序運(yùn)行時(shí),都會(huì)由 MyBatis 組合成 SOL 語句來執(zhí)行需要的操作。
執(zhí)行程序后,控制臺(tái)的輸出結(jié)果如圖所示。
- <resultMap>元素
<resultMap>元素表示結(jié)果映射集,是 MyBatis 中最重要也是最強(qiáng)大的元素。它的主要作回是定義映射規(guī)則、級(jí)聯(lián)的更新以及定義類型轉(zhuǎn)化器等。
<resultMap>元素中包含了一些子元素,它的元素結(jié)構(gòu)如下所示。
<resultMap>元素的 type 屬性表示需要映射的 POJO , id 屬性是這個(gè) resultMap 的唯一標(biāo)識(shí)。 它的子元素<constructor>用于配置構(gòu)造方法(當(dāng)一個(gè) POJO 中未定義無參的構(gòu)造方法時(shí),就可 以使用<constructor>元素進(jìn)行配置)。 子元素<id>用于表示哪個(gè)列是主鍵,而<result>用于表示 POJO 和數(shù)據(jù)表中普通列的映射關(guān)系。 <association>和<collection>用于處理多表時(shí)的關(guān)聯(lián)關(guān) 系,而<discriminator>元素主要用于處理一個(gè)單獨(dú)的數(shù)據(jù)庫查詢返回很多不同數(shù)據(jù)類型結(jié)果集的情況。
在默認(rèn)情況下, MyBatis 程序在運(yùn)行時(shí)會(huì)自動(dòng)地將查詢到的數(shù)據(jù)與需要返回的對(duì)象的屬性進(jìn)行匹配賦值(需要表中的列名與對(duì)象的屬性名稱完全一致)。 然而實(shí)際開發(fā)時(shí),數(shù)據(jù)表中的列和需要返回的對(duì)象的屬性可能不會(huì)完全一致,這種情況下 MyBatis 是不會(huì)自動(dòng)賦值的。 此時(shí),就可以使用<resultMap>元素進(jìn)行處理。
接下來,通過一個(gè)具體的案例來演示<resultMap>元素在此種情況的使用,具體步驟如下。
( 1 )在 mybatis 數(shù)據(jù)庫中,創(chuàng)建一個(gè) t_user 表,并插入幾條測(cè)試數(shù)據(jù)。
( 2 )在 com.neuedu.po 包中,創(chuàng)建持久化類 User,并在類中定義 id、 name 和 age 屬性, 以及其 getter/setter 方法和 toString()方法,文件如下所示。package com.neuedu.po; public class User { private Integer id; private String name; private Integer age; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "User [id=" + id + ", name=" + name + ", age=" + age + "]"; } }( 3 )在 com.neuedu.mapper 包下,創(chuàng)建映射文件 UserMapper.xml ,并在映射文件中編寫映射查詢語句,文件如下所示。
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.neuedu.mapper.UserMapper.xml"> <resultMap type="com.neuedu.po.User" id="resultMap"> <id property="id" column="t_id"/> <result property="name" column="t_name"/> <result property="age" column="t_age"/> </resultMap> <select id="findAllUser" resultMap="resultMap"> select * from t_user </select> </mapper>在上述文件中, <resultMap>的子元素<id>和<result>的 property 屬性表示 User 類的屬性名, column 屬性表示數(shù)據(jù)表 t_user 的列名。 <select>元素的 resultMap 屬性表示引用上面定義的 resultMap。
( 4 )在配置文件 mybatis-config.xml 中,引入 UserMapper.xml。
( 5 )在測(cè)試類中,編寫測(cè)試方法 findAIIUserTest() ,代碼如下所示。@Test public void findAllUserTest() { // 1.讀取配置文件 SqlSession sqlSession = MybatisUtils.getSession(); // 2.SqlSession 執(zhí)行映射文件中定義的 SQL,并返回映射結(jié)果 List<User> users = sqlSession.selectList("com.neuedu.mapper.UserMapper.findAllUser"); for (User user : users) { System.out.println(user); } //3.關(guān)閉 SqlSession sqlSession.close(); }使用 JUnit4 執(zhí)行上述方法后,控制臺(tái)的輸出結(jié)果如圖所示。
從圖可以看出,雖然 t_user 表的列名與 User 對(duì)象的屬性名完全不一樣,但查詢出的數(shù)據(jù)還是被正確地封裝到了 User 對(duì)象中。
除此之外,還可以通過<resultMap>元素中的<association>和<collection>處理多表時(shí)的關(guān)聯(lián)關(guān)系。 關(guān)于關(guān)聯(lián)關(guān)系的內(nèi)容,將在后面章中詳細(xì)講解,這里就不再敘述。
本章小結(jié)
本章主要對(duì) MyBatis 中的核心對(duì)象和核心文件進(jìn)行了詳細(xì)講解。首先講解了 MyBatis 中的兩個(gè)重要核心對(duì)象 SqlSessionFactory 和 SqlSession ;然后介紹了配置文件中的元素及其使用;最后對(duì)映射文件中的幾個(gè)主要元素進(jìn)行了詳細(xì)講解。 通過本章的學(xué)習(xí),大家將能夠了解 MyBatis 中兩個(gè)核心對(duì)象的作用,熟悉配置文件中常用元素的使用,并掌握映射文件中常用元素的使用。






