MyBatis的核心配置
在使用MyBatis框架時,設計兩個核心的d對象:SqlSessionFactory和SqlSession.
SqlsessionFactory
SqlSessionFactory是單個數據庫映射關系經過編譯后的內存鏡像,其主要作用用來創建SqlSession對象,SqlSessionFactory實例對象是可以通過SqlSessionFactoryBulider對象來構建,而SqlSessionFactoryBulider對象可以通過XML文件或者Configuration實例來創建SqlSessionFactory實例,其代碼如下:
//1.讀取配置文件 String resource ="mybatis-config.xml";
InputStream inputStream=Resources.getResourceAsStream(resource); //2.獲取會話工廠對象 SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
注意:SqlSessionFactory對象是線性安全的,它一旦被創建,在整個應用程序間都會存在,如果我們多次的創建同一個SqlSessionFactory對象,那么數據庫的資源很快就會被應用完,為了解決這個問題,通常,一個數據庫是建一個SqlSessionFactory對象的。
SqlSession
SqlSession對象是應用層和持久層之間進行數據庫操作的一個單線程對象,其中主要作用是執行持久化操作,SqlSession對象中包含了所有執行數據庫操作的方法,由於底層封裝了JDBC的連接,所以可以直接使用SqlSession對象來執行已經映射的SQL語句。
注意:每一個線程都應該有自己的SqlSession實例,並且該SqlSession實例是不可共享的,同時,SqlSession是線程不安全的,因此,其使用范圍最好是在一個請求中,或者一個方法中,絕對不能將其放入一個類的靜態字段中,實例字段或者任何類型的管理范圍中,使用完SqlSession后,要及時的關閉它,通常可以將其放入finally塊中關閉。
Sqlsession sqlSession=sqlSessionFactory.openSession(); try{ //執行操作 }finally{ //關閉sqlSession sqlSession.close(); }
使用工具類來創建SqlSession對象
由於每個方法執行都需要獲取配置文件,並根據配置文件的信息來構建SqlSessionFactory對象,然后創建SqlSession對象,這導致了大量重復的代碼,為了簡化開發,可以將重復的代碼封裝到一個工具類中,然后通過這個工具類來創建SqlSession
package com.itheima.util; /** * 工具類 * @author 12428 * */ import java.io.Reader; import org.apache.ibatis.io.Resources; import org.apache.ibatis.jdbc.Null; 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對象 static { try { //使用MyBatis提供的Resource類加載配置文件 Reader reader =Resources.getResourceAsReader("mybatis-config.xml"); //構建SqlSessionFactory對象 sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader); }catch(Exception e) { e.printStackTrace(); } } //獲取SqlSession對象的靜態方法 public static SqlSession getSession() { return sqlSessionFactory.openSession(); } }
二.配置文件
主要元素
在MyBatis核心配置文件中,<configuration>元素是配置文件的根元素,其他的元素都要在其中配置,MyBatis的配置文件mybatis-config.xml中的主要元素如下:
注意:<configuration>的子元素中必須按照由上到下的順序進行配置,否則MyBatis在解析XML配置文件的時候會出錯。
<properties>元素
該元素是一個配置屬性的元素,該元素通常是用於將內部的配置外在化,既通過外部的配置來動態的替換內部定義的屬性。例如,數據庫的來連接屬性,就可以通過Java文件中配置文件來替換,具體如下:
1.在src下創建一個db.properties屬性文件,內容如下:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring
jdbc.username=root
jdbc.password=abc
2.在MyBatis配置文件mybatis-config.xml中的configuration元素中配置子元素<properties>
<properties resource="db.properties"/> //映入外部配置文件
3.修改<dataSource>配置文件中數據庫連接的信息,具體如下。
<!-- 數據庫連接池 --> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </dataSource>
完成了上面的配置后,dataSource中連接數據庫的4個屬性,就可以由db.properties文件中的對應的值來動態的替換。
由於使用properties配置文件來配置屬性值可以方便的在多個配置文件中使用這些屬性,並且方便日后的維護和修改,所以在實際開發中,使用properties配置文件來配置屬性值是最常用的方法。
<typeHandler> 元素
MyBatis在預處理語句(PrparedStatement)中設置了一個參數或者從結果集中取出一個值時,都會使用其框架內部的注冊了的typeHandler(類型處理器)進行相關的處理,typeHandler是將預處理語句中傳入的參數從javaType(java類型)裝換為jdbcType(JDBC)類型,或者從數據庫中取出結果時將jdbcType轉換為javaType類型。MyBatis框架提供了一些默認的類型轉換器,如果提供的類型轉換器不能滿足需求時,可以自定義類型轉換器,自定義類型轉換器可以通過實現TypeHandler接口或者繼承BaseTypeHandle類來定義。
1.注冊一個類的類型處理器:
<typeHandlers> <!--以單個類的形式來配置:handler屬性是用指定在程序中自定義的類型處理器類--> <typeHandler handler="com.itheima.type.CustomtypeHandler"/> </typeHandlers>
2.注冊一個包中的所有類型處理器:
<typeHandlers> <!--注冊一個包中所有的typeHandler,系統會在啟動時會自動掃描包下的所有文件--> <package name="com.itheima.type"/> </typeHandlers>
<environments>元素
在配置文件中,<environments>元素用於對環境進行配置。MyBatis的環境配置實際上是數據源的配置,我們可以通過<environments>元素來配置多種數據源。既配置多種數據庫。
使用該元素進行環境配置時的實例如下:
<!--因為一個environments元素中可以配置多個數據-庫環境<environment>,default屬性是指定使用哪個數據庫環境,該屬性值是<environment>元素的id值->
<environments default="mysql">
<!-- 配置id為mysql的數據庫環境 --> <environment id="mysql">
<!-- 使用JDBC的事務管理 --> <transactionManager type="JDBC"/> <!-- 數據庫連接池 --> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/spring"/> <property name="username" value="root"/> <property name="password" value="abc"/> </dataSource> </environment> </environments>
<environment>元素是<environments>的子元素,該元素可以有多個。在<environment>中包含了事務管理和數據源的配置信息,其中<teansactionManager>是用於配置事務管理,其中它的type屬性是用於指定使用哪種事務管理器;<dataSource>是用於配置數據源,其中的type屬性是用於指定使用哪種數據源。
對於數據源的配置,MyBatis框架提供了UNPOOLED,POOLED,JNDI這三種類型的數據源。
(1)UNPOOLED:配置此數據源后,在每次被請求時會打開和關閉連接,此配置適用於對性能沒有要求的簡單應用程序是一個很好的選擇。
(2)POOLED:此數據源是利用”池“的概念將JDBC連接對象組織起來,避免了在創建新的實例時所需要初始化和認證的時間,這種方法使得並發web應用可以快速的響應,是當前流行的處理方法。
(3)JNDI:此數據源是可以在EJB或者應用服務器上使用,(是從TOMCAT內部來獲取一個內置的數據庫連接池)
<mappers>元素
在配置文件中,<mappers>元素是用來指定Mapper配置文件的位置,一般是使用如下四種方法引入:
1.使用類路勁引入
<mappers> <mapper resource="com/itheima/mapper/UserMapper.xml"/> </mappers>
2.使用本地文件路勁引入
<mappers> <mapper url="file:///D:/com/itheima/mapper/UserMapper.xml"/> </mappers>
3.使用接口類來引入
<mappers> <mapper class="com.itheima.mapper.UserMapper"/> </mappers>
4.使用包名來引入文件
<mappers> <package name="com.itheima.mapper"/> </mappers>
三.映射文件
映射文件是框架中的重要文件,可以說,此框架的強大之處就在於映射文件的編寫上,
1.主要元素
在映射文件中,<mapper>元素是映射文件的根元素,其他元素都是它的子元素,
2.<select>元素
該元素是用於映射查詢語句,它可以幫助我們從數據庫中讀取出數據,並組裝數據庫給業務開發人員
使用select元素執行查詢操作非常簡單,其示例如下
<select id="findCustomerById" parameterType="Integer" resultType="com.itheima.po.Customer"> select * from t_customer where id=#{id} </select>
select元素的常用屬性如下:
屬性 | 說明 |
id | 表示命名空間中的唯一標識符,經常和命名空間namespace一起使用,組合namespace一起使用后如果不唯一,就會拋出錯誤。 |
parameterType | 該屬性是表示傳入sql參數類的全限定名或者別名,它是一個可選屬性。 |
resultType | 該屬性是表示從sql語句中返回結果的類型的全限定名或者別名,如果是集合類型,那么返回的應該是集合里可以包含的類型,而不是集合本身。 |
resultMap | 該屬性是表示外部resultMap的命名引用,返回時可以使用resultMap或者resultType |
flushCache | 表示在調用SQL語句后,是否清除緩之前查詢的本地緩存和二級緩存,默認時false |
useCache | 用於控制二級緩存的開啟和關閉,其值為布爾型,默認為true,表示將查詢結果放在二級緩存里 |
timeout | 用於設置超時參數,單位為秒,超時時將拋出異常 |
fetchSize | 獲取記錄的總條數設置,其默認值是unset(依賴於驅動) |
statementType | 用於設置MyBatis使用哪個JDBC的Statement工作。 |
resultSetType | 表示結果集的類型 |
3<insert>元素
insert元素是用於映射插入語句,在執行完元素中定義的SQL語句后,就會返回一個表示插入記錄數的整數,insert元素的配置實例如下
<insert id="addCustomer" parameterType="com.itheima.po.Customer" flushCache="true" statmentType="PREPARED" keyProperty="" keyColumn="" useGeneratedKeys="" timeout="20"> </insert>
insert元素的屬性大部分和select相同,但是它由三個特定是屬性,這三個屬性如下:
屬性 | 說明 |
keyProperty | (僅對insert和update有用)此屬性的作用是將插入或者更新操作時的返回值賦給PO類的某個屬性,通常會設置為主鍵對應的屬性,如果需要設置聯合主鍵,可以在多個值之間用逗號分開 |
keyColumn | (僅對insert和update有用)此屬性的作用是用於設置第幾行是主鍵,當主鍵列不是表中的第一列是,是需要設置這個屬性,在需要使用主鍵聯合時,值可以使用逗號分開 |
useGeneratedKeys | (僅對insert和update有用)此屬性會使MyBatis使用JDBC的getGeneratedKeys()方法來獲取由數據庫內部產生的主鍵,如MYSql和sql Server等自動生成的主鍵 |
執行查詢操作后,很多時候我們需要返回插入成功的數據生成的主鍵,此時就可以通過上面所講解的3個屬性來實現。
當使用的數據庫支持自動增長時,我們可以通過keyproperty屬性來指定PO類的某個屬性接受主鍵的返回值,同時設置useGeneratedKeys的屬性值為true,其使用如下:
<insert id="addCustomer" parameterType="com.itheima.po.Customer" keyProperty="id" useGeneratedKeys="true"> insert into t_customer(username,jobs,phone) values(#{username},#{jobs},#{phone}) </insert>
使用以上的配置后執行插入操作后,就會返回插入成功的行數,以及插入行的主鍵值,為了驗證配置,可以使用如下代碼測試:
@Test public void addCustomer(){ //獲取SqlSession對象 SqlSession sqlSession=MyBatisUtis.getSession(); Customer customer=new Customer(); customer.setUsername("rose"); customer.setJobs("student"); customer.setPhone("11111111"); int rows=sqlSession.insert("som.itheima.mapper.CustomerMapper.addCustomer",customer); //輸出插入數據的主鍵 System.out.println(customer.getId()); if(rows>0){ system.out.println("您成功插入了"+rows+"行數據!"); }else{ system.out.println("插入失敗!"); } //執行提價事務 sqlSession.commit(); //關閉資源 sqlSession.close(); }
當數據庫不可以支持自動增長時,如Oracle,或者自動增長的數據庫取消了自動增長的規則時,可以使用MyBatis提供的另一種方法來自定義生成主鍵,具體配置如下:
<insert id="addCustomer" parameterType="com.itheima.po.Customer" > <selectKey keyProperty="id" resultType="Integer" order="BEFORE"> 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>
在執行上面代碼時,會先執行<selectKey>中的語句,他會通過自定義的語句來設置主鍵的值,如果t_customer表中的沒有記錄,就將id的值設置為1,如果有id值,就將id值加上1,作為新的主鍵,然后在調用插入語句。
selectKey可以設置的屬性如下:
<selectKey keyProperty="id" resultType="Integer" order="BEFORE" statmentType="PREPARED">
</selectKey>
order屬性可以被設置為BEFORE或者AFTER,如果設置為BREFORE,那么它會先執行<selectKey>中的配置來設置主鍵,然后執行插入語句,如果設置為AFTER,那么它會先執行插入語句,然后再執行<selectKey>中的配置內容。
4.<update>和<delete>元素
這兩個元素的執行非常簡單,它們的配置也基本相同,與<insert>元素一樣,這里兩個元素在執行后,也會返回一個表示影響記錄條數的整數。
5.<sql>元素
<sql>元素是用於定義可重用的SQL片段,然后在其他的語句中引用這一片代碼,例如定義一個包含了id,username,jobs,phone字段的代碼片段如下:
<sql id="customerColumns">id,username,jobs,phone</sql>
引用此代碼如下:
<select id="findCustomerById" parameterType="Integer" resultType="com.itheima.po.Customer"> select <include refid="customerColumns"/> from t_customer where id=#{id} </select>
使用<include>元素的refid屬性可以引用自定義的代碼片段,refid屬性值自定義代碼段的id值。
6.<resultMap>元素
該元素是用於配置查詢返回的結果與JavaBean類之間的映射關系,是MyBatis中最強大的元素。它的主要作用是定義映射規則,級聯的更新,以及定義類型轉換器。
<resultMap>元素包含了一些子元素,他的結構如下:
<!--resultMap元素的結構 --> <resultMap type="" id=""> <!--類在實例化時,用來注入結果到構造方法中--> <constructor> <idArg/> <!--ID參數:標記結果作為Id--> <arg/> <!--注入到構造方法中的一個普通結果--> </constructor> <id/> <!--用來表示哪個列示主鍵--> <result> <!--注入到字段或者JavaBean屬性的普通結果--> <association property=""/> <!--用於一對一關聯--> <collection property=""/> <!--用於一對多關聯--> <discriminator javaType=""> <case value=""/> <!--基於某些值的結果映射--> </discriminator> </resultMap>
該元素的type屬性是表示需要映射的POJO,id屬性是這個resultMap的唯一標識,它的子元素<constructor>用於配置構造方法,當一個POJO中未定義無參數的構造方法時,就可以使用<constructor>配置。子元素<id>是用於表示哪個鍵是主鍵,而<result>是用於表示普通POJO和數據表中普通列的映射關系,<association>和<collection>用於配置處理多表時的關聯關系。而<discriminator>是用於處理一個單獨的數據庫查詢返回很多不同數據類型結果集的情況。
在默認的情況下,MyBatis程序在運行時會自動的將查詢到 的結果和需要返回的對象的屬性進行匹配復制(需要表中的列和對象的屬性名完全一致。然而,在現實中,數據表中的列和需要返回的對象屬性可能並不是完全一樣,這時,就可以使用該元素進行處理。