MyBatis 真正的力量是在映射語句中。這裏是奇蹟發生的地方。對於全部的力量,SQL 映射的 XML 文件是至關的簡單。固然若是你將它們和對等功能的 JDBC 代碼來比較,你會發現映射文件節省了大約 95%的代碼量。MyBatis 的構建就是聚焦於 SQL 的,使其遠離於普通的方式。html
SQL 映射文件有不多的幾個頂級元素(按照它們應該被定義的順序):java
參閱這篇文章裏的二級緩存段落 MyBatis緩存詳解sql
用來定義可重用的sql語句塊。數據庫
<sql id="column"> name,species,sex </sql>
而後在sql映射中用<include/>標籤引入:apache
<select id="selectPetByName" parameterType="string" resultType="hashmap"> select <include refid="column"/> from pet where name = #{name} </select>
這樣就能夠減小大量重複的sql書寫工做。緩存
resultMap是mybatis中最強大最有用的配置,它能夠幫助咱們告別繁瑣的while + resultSet.get(..) 而實現自動封裝。mybatis
對於簡單的sql查詢,不須要配置resultMap,用hashmap來封裝結果集會更好,這樣會以字段名稱爲key,字段值爲value來封裝結果集:dom
<select id="selectAllColumn" parameterType="string" resultType="hashmap"> select <include refid="column"/> from pet where name = #{name} </select>
但有時咱們須要獲得一個JavaBean對象,有兩種方式能夠實現,一種用reusltType來制定結果類型,另外一種用resultMap來映射結果集和JavaBean對象:ide
第一種方式:post
<select id="selectOneByName" parameterType="string" resultType="com.mybatis.test.entity.Pet"> select <include refid="column"/> from pet where name = #{name} </select>
這樣mybatis就會把查詢出的結果封裝到Pet對象中。
第二種方式:
配置resultMap
<resultMap type="com.mybatis.test.entity.Pet" id="petMap"> <result column="name" property="name" javaType="string" jdbcType="VARCHAR"/> <result column="species" property="species" javaType="string" jdbcType="VARCHAR" typeHandler="com.mybatis.test.handler.MyStringTypeHandler"/> <result column="sex" property="sex" typeHandler="com.mybatis.test.handler.MyStringTypeHandler"/> </resultMap>
在sql映射中配置resultMap:
<select id="cthSelect" resultMap="petMap"> select <include refid="column"/> from pet </select>
實際上應用第一種配置方式時,mybatis會在幕後根據字段名稱自動建立一個resultMap。若表字段名稱與JavaBean中的字段名稱不匹配,還能夠利用sql語句的as來修改sql結果集的字段名,使之與JavaBean中的字段名相匹配:
<select id="selectOneByName" parameterType="string" resultType="com.mybatis.test.entity.Pet"> select name as name, species as species, sex as sex from pet where name = #{name} </select>
但有的時候事情並無這麼簡單,咱們在不少狀況下須要作一對多或多對一的聯合查詢,但把這些重組的字段再組合到一個新的bean對象中是不現實的,這樣就須要對多個表和bean利用resultMap作聯合配置,以知足實際的需求。
下面以經典的「部門」對「員工」爲例,作一對多和多對一的映射配置:
Employee Bean:
private Integer id; private String employeeName; private Integer age; private Department department = new Department();
Department Bean:
private Integer id; private String departmentName; private List<Employee> employees;
一個部門對應多個員工,而一個員工屬於一個部門,咱們分別從部門和員工的角度出發,來作一對多和多對一的映射。
員工-部門的多對一映射:
<resultMap type="com.mybatis.test.entity.Employee" id="employeeMap"> <!-- id : 一個 ID 結果;標記結果做爲 ID 能夠幫助提升總體效能. result : 注入到字段或 JavaBean 屬性的普通結果 association : 一個複雜的類型關聯;許多結果將包成這種類型. collection : 複雜類型的集 --> <id property="id" column="id"/> <result property="employeeName" column="name"/> <result property="age" column="age"/> <association property="department" javaType="Department"> <id property="id" column="id"/> <result property="departmentName" column="department_name"/> </association> </resultMap>
用<association/>來指定每個員工多對應的部門。
部門-員工的一對多映射:
<resultMap type="Department" id="departmentMap"> <id property="id" column="id"/> <result property="departmentName" column="department_name"/> <collection property="employees" ofType="Employee" column="dept_id"> <id property="id" column="id"/> <result property="employeeName" column="name"/> <result property="age" column="age"/> </collection> </resultMap>
利用<collection/>來制定可能是一方。在配置多對一關係時,須要在<collection/>中制定關聯字段,column="dept_id",這樣mybatis就會根據這個字段來找出全部屬於該部門的員工,並將其封裝到集合中。
在定義resultMap時,還能夠利用javaType、jdbcType和typeHandler來實現java數據類型和數據庫字段類型的對應關係及其特定的操做動做,eg:
在mybatis核心配置文件中生命自定義類型處理器:
<typeHandlers> <typeHandler javaType="string" jdbcType="VARCHAR" handler="com.mybatis.test.handler.MyStringTypeHandler"/> </typeHandlers>
自定義類型處理器:
package com.mybatis.test.handler; import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import org.apache.ibatis.type.JdbcType; import org.apache.ibatis.type.TypeHandler; public class MyStringTypeHandler implements TypeHandler<String>{ @Override public void setParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException { if("".equals(parameter) || "null".equals(parameter) || parameter == null || "NULL".equals(parameter)){ parameter = "blank"; } ps.setString(i, parameter); } @Override public String getResult(ResultSet rs, String columnName) throws SQLException { String result = rs.getString(columnName); if("null".equals(result) || "".equals(result) || result == null || "NULL".equals(result)){ result = "blank"; } return result; } @Override public String getResult(ResultSet rs, int columnIndex) throws SQLException { String result = rs.getString(columnIndex); if("null".equals(result) || "".equals(result) || result == null || "NULL".equals(result)){ result = "blank"; } return result; } @Override public String getResult(CallableStatement cs, int columnIndex) throws SQLException { String result = cs.getString(columnIndex); if("null".equals(result) || "".equals(result) || result == null || "NULL".equals(result)){ result = "blank"; } return null; } }
該類型處理器既能夠用於設置參數時、也能夠用於獲取結果時對空值的處理。
在resultMap中進行配置:
<resultMap type="com.mybatis.test.entity.Pet" id="petMap"> <result column="name" property="name" javaType="string" jdbcType="VARCHAR"/> <result column="species" property="species" javaType="string" jdbcType="VARCHAR" typeHandler="com.mybatis.test.handler.MyStringTypeHandler"/> <result column="sex" property="sex" typeHandler="com.mybatis.test.handler.MyStringTypeHandler"/> </resultMap>
這樣,若是從數據庫表中查詢出的結果爲null時,就會用自定義類型處理器中的方式進行處理。
在設置參數的時候能夠像下面這樣應用自定義類型處理器對參數進行處理:
<insert id="insertNullByMyTypeHandler" parameterType="Pet"> insert into pet (<include refid="column"/>) values ( #{name,jdbcType=UNDEFINED,javaType=string,handler=com.mybatis.test.handler.MyTypeHandler}, #{species}, #{sex} ) </insert>
3)insert、update、delete
這三個標籤分別配置對應的sql語句,因爲這三中sql都是DML,因此在用法上基本相同:
<insert id="insertAuthor" parameterType="domain.blog.Author" flushCache="true" statementType="PREPARED" keyProperty="" keyColumn="" useGeneratedKeys="" timeout="20"> <update id="insertAuthor" parameterType="domain.blog.Author" flushCache="true" statementType="PREPARED" timeout="20"> <delete id="insertAuthor" parameterType="domain.blog.Author" flushCache="true" statementType="PREPARED" timeout="20">
id:該sql語句在當前名稱空間下的惟一標識符,用戶調用該sql語句。
parameterType:sql語句的參數類型,能夠是mybatis提供的別名(int、string、hashmap、list等),也能夠是自定義相似。須要注意的是,若參數類型爲hashmap或自定義bean等,在利用#{fieldName}取得參數的值時用到的名稱須要與map中的key或bean中的字段名稱保證一致,不然會取不到數據,若是是string或int等,則名稱沒有現實,只起到標識的做用。
flushCache:刷新緩存,若將該屬性設置爲true,則調用該sql時,會到時緩存被清空。默認爲false。
statementType:設置預編譯sql語句的方式,mybatis提供了三種:
STATEMENT,PREPARED,CALLABLE
默認是PREPARED類型。
timeout:設置獲取數據庫操做結果的最大等事件。默認不對其進行設置,有數據庫取得來決定。
4)select
select語句是最經常使用的數據庫操做,相對於DML操做,mybatis對select語句映射的支持明顯更強。查詢語句的特殊之處在於既有輸入也有輸出,下面對select語句映射作簡要概述。
一個最簡單的查詢映射:
<select id="selectPerson" parameterType="int" resultType="hashmap"> SELECT * FROM PERSON WHERE ID = #{id} </select>
該語句按照id查詢一條person記錄,其中輸入參數是int類型,雖然#{id}中的id與數據表中的id列名保存一致,但前面已經說過,對於基本數據類型的參數,名稱沒有現實,任何名字mybatis均可以取到參數的值。返回結果是hashmap,也就是Java中對應的HashMap,定義該結果類型後,mybatis會將查詢結果封裝到一個map對象中,key值爲字段名稱,value爲該字段的值。
Mybatis對select標籤提供了豐富的屬性,以支持對select語句的更細粒度配置:
<select id="selectPerson" parameterType="int" parameterMap="deprecated" resultType="hashmap" resultMap="personResultMap" flushCache="false" useCache="true" timeout="10000" fetchSize="256" statementType="PREPARED" resultSetType="FORWARD_ONLY">
其中的本分屬性前面已經介紹過,這裏就不在冗述了。 useCache:配置二級緩存,當mybatis開啓二級緩存時,查詢有默認是應用二級緩存的,若不想將某一個DQL與二級緩存聯繫起來,可將該屬性設置爲false。 fetchSize:設置每次查詢的最大返回結果,一般不設置改屬性。