MyBatis四對映器
阿新 • • 發佈:2019-02-07
對映器,是MyBatis最強大的工具,也是我們使用MyBatis用的最多的工具,因此熟練掌握它十分必要。MyBatis是針對對映器構造的SQL構建的輕量級框架,
並且通過配置生成對應的JavaBean返回給呼叫者,而這些配置主要便是對映器。
一、對映器元素
select查詢語句
insert插入語句
update更新語句
delete刪除語句
parameterMap定義引數的對映關係
sql允許定義一部分SQL然後在各個地方引用,如whereSQL
resultMap用來描述從資料庫結果集中來載入物件,它是最複雜、最強大的元素
cache給定名稱空間的快取配置
cache-ref其他名稱空間快取配置的引用
select 元素
id、parameterType(引數)、resultType(返回的結果型別不能與resultMap同時使用)、resultMap(強大的對映集的引用)、flushCache(是否清除二級快取和本地快取)、
useCache(是否開啟二級快取)、databaseId(資料庫廠商)、
自動對映:
引數autoMappingBehavior,當它不為空的NONE的時候,MyBatis會提供自動對映的功能,只要返回的SQL列名和JavaBean的屬性名是一樣的就行,
實際情況下我們使用別名的機制或者配置mapUnderscoreToCamelCase為true,就可以實現自動對映的功能。
多個引數:
1、使用map傳遞引數
<select id='id' parmeterType="map" resultMap="roleMap">
select * from T_role where id=#{roleName}
</select>
public List<Role> findRoleByMap(<Map<String,String> params);
2、使用註解
public List<Role> findRoleBy(@Param("roleName") String roleName,@Param("note") String note);
<select id='id' resultMap="roleMap">
select * from T_role where id=#{roleName} and note=#{note}
</select>
3、使用JavaBean傳遞引數
<select id='id' parmeterType="com.beans.bean" resultMap="roleMap">
select * from T_role where id=#{roleName} and note=#{note}
</select>
public List<Role> findRoleByParams(Bean bean)
resultMap:
在處理複雜的對映的時候,使用resultMap,我們需要在對映器中定義resultMap
<resultMap id="roleResultMap" type="come.bean.Role">
<id property="id" column="id"/>
<result property="roleName" column="role_name"/>
<result property="note" column="note"/>
</resultMap>
<select parameterType="long" id="getRole" resultMap="roleResultMap">
select id,role_name,note from t_role where id=#{id}
</select>
insert元素,myBatis會在執行插入之後返回一個整數,表示執行操作後插入的記錄數
id、parameterType(引數)、flushCache(是否清除快取)、keyProperty(表示哪個列作為屬性的主鍵,不能和keyColumn同時使用)、
useGeneratedKeys(使MyBatis使用JDBC的getGeneratedKeys方法來取出由資料庫內部生產的主鍵,使用了它就必須給keyColumn或者可以keyProperty賦值)、
keyColumn(指明第幾列,用整形)、databaseId(指定資料庫廠商)
<insert parameterType="role" id="insertRole" useGeneratedKeys="true" keyProperty="id">
insert into t_role(role_name,note) values(#{roleName},#{note})
</insert>
自動增長的不適用的情況下,可能要指定增長規則,則使用selectKey
selectKey:
<insert parameterType="role" id="insertRole" useGeneratedKeys="true" keyProperty="id">
<selectKey keyProperty="id" resultType="int" order="BEFORE">
select if(max(id) is null,1,max(id)+2) as newId from t_role
</selectKey>
insert into t_role(id,role_name,note) values(#{id},#{roleName},#{note})
</insert>
order 有BEFORE和AFTER,根據不同資料庫生成主鍵的機制取不同值,
1:BEFORE,會先選擇主鍵,然後設定keyProperty,再執行insert語句;
2:AFTER,就先執行insert 語句再執行selectKey 語句。
在Oracle經常使用序列、在MySQL中使用函式來自動生成插入表的主鍵
update和delete,返回一個整數,表示執行後影響的條數
<update parameterType="role" id="updateRole">
update t_role set
role_name=#{role_name},
note=#{note}
where id=#{id}
</update>
<delete parameterType="long" id="delete">
delete from T_role where id=#{id}
</delete>
引數:
我們可以通過指定引數的型別去讓對應的typeHandler處理它們,定義引數屬性的時候,MyBatis不允許換行。
#{age,javaType=int,jdbcType=NUMERIC}
#{age,javaType=int,jdbcType=NUMERIC,typeHandler=MyTypeHandler}
#{age,javaType=int,jdbcType=NUMERIC,numericScale=2}//設定儲存的精度
儲存過程:
對於儲存過程而言,存在三種引數,IN、OUT、INOUT,MyBatis的引數規則為其提供了良好的支援,我們通過制定mode屬性來確定其是哪一種引數。當引數為OUT或者為INOUT的時候,
MyBatis會將儲存過程返回的結果設定到你制定的引數中。當你返回的是一個遊標(JdbcType=CURSOR)的時候,你還需要去設定resultMap以便MyBatis將儲存過程的引數對映到對
應的型別,這時候MyBatis就會通過你所設定的resultMap自動為你設定對映結果。
#{role,mode=OUT,jdbcType=CURSOR,javaType=ResultSet,resultMap=myResultMap}//javaType可選,MyBatis會自動檢測它
同時,MyBatis還支援結構體,需要指定語句型別的名稱(jdbcTypeName=my_type這樣)
主要,當欄位返回值可能是空null的時候,我們需要去指定欄位型別,因為null值MyBatis無法判斷其型別。
#{roleNo},#{roleName},#{note,jdbcType=VARCHAR}
特殊字串替換和處理(#和$)
在MyBatis中我們經常傳遞字串,我們設定的的引數#{name}在大部分情況下MyBatis會用建立預編譯的語句,然後MyBatis為它設值,然而我們有時候需要的是
傳遞SQL本身而不是SQL所需要的引數,如動態列的時候,我們需要用程式傳遞資料列,每次查詢的列可能不同,此時我們不希望MyBatis去轉譯這些引數,
就用${},就不會使用預編譯
select ${columns} from t_tablename where role_id=#{roleId}
這樣MyBatis就不會幫我們轉譯column了,而變為直出,預編譯為以下內容。
seelct table_name from t_talename where role_id=?
sql元素:我們可以定義一串SQL語句的組成部分,其他的語句可以通過引用來使用它
<sql id="pageBeginSql">
select * from (select tz.*, rownum row_num
from (
</sql>
<sql id="pageEndSql">
) tz where rownum <= #{endNum}) where row_num >= #{beginNum}
</sql>
<select>
<include refid="pageBeginSql">
select * from t_role
<include refid="pageEndSql">
<select>
resultMap:
它的作用是定製對映規則、級聯的更新、定製型別裝換器等。MyBatis現有的版本只支援resultMap查詢,不支援更新或者儲存,
更不必說級聯的更新、刪除和修改了。
<resultMap>
<constructor>
<idArg/>
<arg>
</constructor>
<id/>
<result/>
<association/>
<collection/>
<descriminator>
<case/>
</descriminator>
</resultMap>
其中constructor元素用於配置構造方法,一個POJO可能不存在沒有引數的構造方法,這個時候我們就是用constructor進行配置。
<resultMap ......>
<constructor>
<idArg column="id" >
<arg column="role_name" javaType="string">
</constructor>
......
</resultMap>
儲存結果集
一、map
一般而言,任何的select語句都可以使用map儲存。
<select id="findColorByNote" parameterType="string" resultType="map">
select * from t_role where 1=1 and note like concat('%',#{note},'%')
</select>
二、使用POJO儲存結果
<resultMap id="roleMap" type="com.kang.Role">
<id property="id" column="id"/>
<result property="roleName" column="role_name"/>
</resultMap>
<select parameterType="long" id="getRole" resultMap="roleMap">
select * from t_role where id=#{id}
</select>
級聯
association 一對一
<mapper namespace="com.kang.studentSelfcardMapper" >
<resultMap type="com.kang.StudentSelfcardBean" id="studentSelfcardMap">
<id property="id" column="id">
<result property="studentId" column="student_id"/>
<result property="SelfName" column="self_name"/>
<select id="findStudentSelfcardByStudentId" paramterType="int" resultMap="studentSelfcardMap">
select * from t_role where id=#{id}
</select>
</resultMap>
<mapper>
<mapper namespace="com.kang.studentMapper" >
<resultMap type="com.kang.StudentBean" id="studentMap">
<id property="id" column="id">
<result property="studentId" column="student_id"/>
<result property="studentName" column="student_name"/>
<association property="studentSelfcard" column='id' select="com.kang.studentSelfcardMapper.findStudentSelfcardByStudentId"></association>
<select id="getStudent" paramterType="int" resultMap="studentMap">
select * from t_role where id=#{id}
</select>
</resultMap>
<mapper>
column='id'是傳遞的引數,可以多個,用“,”號隔開
collection 一對多
<mapper namespace="com.kang.studentMapper" >
<resultMap type="com.kang.StudentBean" id="studentMap">
<id property="id" column="id">
<result property="studentId" column="student_id"/>
<result property="studentName" column="student_name"/>
<collection property="studentLectureList" column='id' select="com.kang.studentLectureMapper.getStudentLectureByStuId"></collection>
</resultMap>
<select id="getStudent" paramterType="int" resultMap="studentMap">
select * from t_role where id=#{id}
</select>
<mapper>
<mapper namespace="com.kang.studentLectureMapper" >
<resultMap type="com.kang.StudentLectureBean" id="studentLectureMap">
<id property="id" column="id">
<result property="studentId" column="student_id"/>
<result property="grade" column="grade"/>
</resultMap>
<select id="getStudentLectureByStuId" paramterType="int" resultMap="studentLectureMap">
select * from t_lecture where stu_id=#{id}
</select>
<mapper>
discriminator 鑑別器,可以根據實際選擇採用哪個類作為例項,允許你根據特定的條件去關聯不同的結果集
效能分析和N+1問題
級聯就會出現著名的N+1問題了,和其他ORM框架一樣MyBatis也有延遲載入的功能,兩個全域性引數lazyLoadingEnable和aggressiveLazyLoading
lazyLoadingEnable:是否開啟延遲載入功能
<settings>
<setting name="lazyLoadingEnable" value="true"></setting>
</settings>
也可以在association和collection中使用fetchType="lazy"、"eager"來設定
aggressiveLazyLoading是否按層級載入,MyBatis預設情況下是使用層級載入策略,即同一級的延遲資料只要載入其中一個,其餘就會全部加載出來,
此時用aggressiveLazyLoading = false 就是按需載入。延遲載入的原理是動態代理。
快取:
快取就是把資料儲存在計算機的記憶體上,讀取的時候無需在從磁碟讀入,因此具備快速讀取和使用的特點,如果快取命中率高,可以極大的提高系統的效能。
使用快取的關鍵在於儲存內容訪問的命中率。目前流行的快取伺服器有MongoDB、Redis、Ehcache等。
一級快取:MyBatis對快取提供支援,但是在沒有配置的預設情況下,它只開啟一級快取,一級快取只是相對於SqlSession而言,各個SqlSession是相互隔離的;
二級快取:SqlSessionFactory層面的二級快取是不開啟的,二級快取需要配置<cache/>元素,MyBatis要求返回的POJO是可序列化的,
也就是實現Serializable介面。
<cache eviction="LRU" flushInterval="100000" size="1024" readOnly=true"/>
eviction:快取回收策略
flushInterva:重新整理間隔時間
size:引用數目
readyOnly:只讀,意味著快取資料只能讀取不能修改
自定義快取:
在大型伺服器上,會使用各類不同的快取伺服器,這個時候我們可以定製快取,比如現在流行的redis快取,我們需要實現,org.apache.ibatis.cache.Cache
根據不同的快取做不同的實現,做完實現後,再配置
<cache type="com.kang.MyCache">
<property name="host" value="localhost"/> <!--可以配置一些快取中常用的屬性 -->
</cache>
在MyCache增加setHost方法,初始化的時候,會被呼叫到,這樣就可以對自定義設定一些外部引數
我們也可以配置SQL層面的快取機制,來決定它們是否需要使用或者重新整理快取,根據useCache和flushCache兩個屬性來完成,useCache標誌是否使用,
flushCache標誌插入後是否需要重新整理
並且通過配置生成對應的JavaBean返回給呼叫者,而這些配置主要便是對映器。
一、對映器元素
select查詢語句
insert插入語句
update更新語句
delete刪除語句
parameterMap定義引數的對映關係
sql允許定義一部分SQL然後在各個地方引用,如whereSQL
resultMap用來描述從資料庫結果集中來載入物件,它是最複雜、最強大的元素
cache給定名稱空間的快取配置
cache-ref其他名稱空間快取配置的引用
select 元素
id、parameterType(引數)、resultType(返回的結果型別不能與resultMap同時使用)、resultMap(強大的對映集的引用)、flushCache(是否清除二級快取和本地快取)、
useCache(是否開啟二級快取)、databaseId(資料庫廠商)、
自動對映:
引數autoMappingBehavior,當它不為空的NONE的時候,MyBatis會提供自動對映的功能,只要返回的SQL列名和JavaBean的屬性名是一樣的就行,
實際情況下我們使用別名的機制或者配置mapUnderscoreToCamelCase為true,就可以實現自動對映的功能。
多個引數:
1、使用map傳遞引數
<select id='id' parmeterType="map" resultMap="roleMap">
select * from T_role where id=#{roleName}
</select>
public List<Role> findRoleByMap(<Map<String,String> params);
2、使用註解
public List<Role> findRoleBy(@Param("roleName") String roleName,@Param("note") String note);
<select id='id' resultMap="roleMap">
select * from T_role where id=#{roleName} and note=#{note}
</select>
3、使用JavaBean傳遞引數
<select id='id' parmeterType="com.beans.bean" resultMap="roleMap">
select * from T_role where id=#{roleName} and note=#{note}
</select>
public List<Role> findRoleByParams(Bean bean)
resultMap:
在處理複雜的對映的時候,使用resultMap,我們需要在對映器中定義resultMap
<resultMap id="roleResultMap" type="come.bean.Role">
<id property="id" column="id"/>
<result property="roleName" column="role_name"/>
<result property="note" column="note"/>
</resultMap>
<select parameterType="long" id="getRole" resultMap="roleResultMap">
select id,role_name,note from t_role where id=#{id}
</select>
insert元素,myBatis會在執行插入之後返回一個整數,表示執行操作後插入的記錄數
id、parameterType(引數)、flushCache(是否清除快取)、keyProperty(表示哪個列作為屬性的主鍵,不能和keyColumn同時使用)、
useGeneratedKeys(使MyBatis使用JDBC的getGeneratedKeys方法來取出由資料庫內部生產的主鍵,使用了它就必須給keyColumn或者可以keyProperty賦值)、
keyColumn(指明第幾列,用整形)、databaseId(指定資料庫廠商)
<insert parameterType="role" id="insertRole" useGeneratedKeys="true" keyProperty="id">
insert into t_role(role_name,note) values(#{roleName},#{note})
</insert>
自動增長的不適用的情況下,可能要指定增長規則,則使用selectKey
selectKey:
<insert parameterType="role" id="insertRole" useGeneratedKeys="true" keyProperty="id">
<selectKey keyProperty="id" resultType="int" order="BEFORE">
select if(max(id) is null,1,max(id)+2) as newId from t_role
</selectKey>
insert into t_role(id,role_name,note) values(#{id},#{roleName},#{note})
</insert>
order 有BEFORE和AFTER,根據不同資料庫生成主鍵的機制取不同值,
1:BEFORE,會先選擇主鍵,然後設定keyProperty,再執行insert語句;
2:AFTER,就先執行insert 語句再執行selectKey 語句。
在Oracle經常使用序列、在MySQL中使用函式來自動生成插入表的主鍵
update和delete,返回一個整數,表示執行後影響的條數
<update parameterType="role" id="updateRole">
update t_role set
role_name=#{role_name},
note=#{note}
where id=#{id}
</update>
<delete parameterType="long" id="delete">
delete from T_role where id=#{id}
</delete>
引數:
我們可以通過指定引數的型別去讓對應的typeHandler處理它們,定義引數屬性的時候,MyBatis不允許換行。
#{age,javaType=int,jdbcType=NUMERIC}
#{age,javaType=int,jdbcType=NUMERIC,typeHandler=MyTypeHandler}
#{age,javaType=int,jdbcType=NUMERIC,numericScale=2}//設定儲存的精度
儲存過程:
對於儲存過程而言,存在三種引數,IN、OUT、INOUT,MyBatis的引數規則為其提供了良好的支援,我們通過制定mode屬性來確定其是哪一種引數。當引數為OUT或者為INOUT的時候,
MyBatis會將儲存過程返回的結果設定到你制定的引數中。當你返回的是一個遊標(JdbcType=CURSOR)的時候,你還需要去設定resultMap以便MyBatis將儲存過程的引數對映到對
應的型別,這時候MyBatis就會通過你所設定的resultMap自動為你設定對映結果。
#{role,mode=OUT,jdbcType=CURSOR,javaType=ResultSet,resultMap=myResultMap}//javaType可選,MyBatis會自動檢測它
同時,MyBatis還支援結構體,需要指定語句型別的名稱(jdbcTypeName=my_type這樣)
主要,當欄位返回值可能是空null的時候,我們需要去指定欄位型別,因為null值MyBatis無法判斷其型別。
#{roleNo},#{roleName},#{note,jdbcType=VARCHAR}
特殊字串替換和處理(#和$)
在MyBatis中我們經常傳遞字串,我們設定的的引數#{name}在大部分情況下MyBatis會用建立預編譯的語句,然後MyBatis為它設值,然而我們有時候需要的是
傳遞SQL本身而不是SQL所需要的引數,如動態列的時候,我們需要用程式傳遞資料列,每次查詢的列可能不同,此時我們不希望MyBatis去轉譯這些引數,
就用${},就不會使用預編譯
select ${columns} from t_tablename where role_id=#{roleId}
這樣MyBatis就不會幫我們轉譯column了,而變為直出,預編譯為以下內容。
seelct table_name from t_talename where role_id=?
sql元素:我們可以定義一串SQL語句的組成部分,其他的語句可以通過引用來使用它
<sql id="pageBeginSql">
select * from (select tz.*, rownum row_num
from (
</sql>
<sql id="pageEndSql">
) tz where rownum <= #{endNum}) where row_num >= #{beginNum}
</sql>
<select>
<include refid="pageBeginSql">
select * from t_role
<include refid="pageEndSql">
<select>
resultMap:
它的作用是定製對映規則、級聯的更新、定製型別裝換器等。MyBatis現有的版本只支援resultMap查詢,不支援更新或者儲存,
更不必說級聯的更新、刪除和修改了。
<resultMap>
<constructor>
<idArg/>
<arg>
</constructor>
<id/>
<result/>
<association/>
<collection/>
<descriminator>
<case/>
</descriminator>
</resultMap>
其中constructor元素用於配置構造方法,一個POJO可能不存在沒有引數的構造方法,這個時候我們就是用constructor進行配置。
<resultMap ......>
<constructor>
<idArg column="id" >
<arg column="role_name" javaType="string">
</constructor>
......
</resultMap>
儲存結果集
一、map
一般而言,任何的select語句都可以使用map儲存。
<select id="findColorByNote" parameterType="string" resultType="map">
select * from t_role where 1=1 and note like concat('%',#{note},'%')
</select>
二、使用POJO儲存結果
<resultMap id="roleMap" type="com.kang.Role">
<id property="id" column="id"/>
<result property="roleName" column="role_name"/>
</resultMap>
<select parameterType="long" id="getRole" resultMap="roleMap">
select * from t_role where id=#{id}
</select>
級聯
association 一對一
<mapper namespace="com.kang.studentSelfcardMapper" >
<resultMap type="com.kang.StudentSelfcardBean" id="studentSelfcardMap">
<id property="id" column="id">
<result property="studentId" column="student_id"/>
<result property="SelfName" column="self_name"/>
<select id="findStudentSelfcardByStudentId" paramterType="int" resultMap="studentSelfcardMap">
select * from t_role where id=#{id}
</select>
</resultMap>
<mapper>
<mapper namespace="com.kang.studentMapper" >
<resultMap type="com.kang.StudentBean" id="studentMap">
<id property="id" column="id">
<result property="studentId" column="student_id"/>
<result property="studentName" column="student_name"/>
<association property="studentSelfcard" column='id' select="com.kang.studentSelfcardMapper.findStudentSelfcardByStudentId"></association>
<select id="getStudent" paramterType="int" resultMap="studentMap">
select * from t_role where id=#{id}
</select>
</resultMap>
<mapper>
column='id'是傳遞的引數,可以多個,用“,”號隔開
collection 一對多
<mapper namespace="com.kang.studentMapper" >
<resultMap type="com.kang.StudentBean" id="studentMap">
<id property="id" column="id">
<result property="studentId" column="student_id"/>
<result property="studentName" column="student_name"/>
<collection property="studentLectureList" column='id' select="com.kang.studentLectureMapper.getStudentLectureByStuId"></collection>
</resultMap>
<select id="getStudent" paramterType="int" resultMap="studentMap">
select * from t_role where id=#{id}
</select>
<mapper>
<mapper namespace="com.kang.studentLectureMapper" >
<resultMap type="com.kang.StudentLectureBean" id="studentLectureMap">
<id property="id" column="id">
<result property="studentId" column="student_id"/>
<result property="grade" column="grade"/>
</resultMap>
<select id="getStudentLectureByStuId" paramterType="int" resultMap="studentLectureMap">
select * from t_lecture where stu_id=#{id}
</select>
<mapper>
discriminator 鑑別器,可以根據實際選擇採用哪個類作為例項,允許你根據特定的條件去關聯不同的結果集
效能分析和N+1問題
級聯就會出現著名的N+1問題了,和其他ORM框架一樣MyBatis也有延遲載入的功能,兩個全域性引數lazyLoadingEnable和aggressiveLazyLoading
lazyLoadingEnable:是否開啟延遲載入功能
<settings>
<setting name="lazyLoadingEnable" value="true"></setting>
</settings>
也可以在association和collection中使用fetchType="lazy"、"eager"來設定
aggressiveLazyLoading是否按層級載入,MyBatis預設情況下是使用層級載入策略,即同一級的延遲資料只要載入其中一個,其餘就會全部加載出來,
此時用aggressiveLazyLoading = false 就是按需載入。延遲載入的原理是動態代理。
快取:
快取就是把資料儲存在計算機的記憶體上,讀取的時候無需在從磁碟讀入,因此具備快速讀取和使用的特點,如果快取命中率高,可以極大的提高系統的效能。
使用快取的關鍵在於儲存內容訪問的命中率。目前流行的快取伺服器有MongoDB、Redis、Ehcache等。
一級快取:MyBatis對快取提供支援,但是在沒有配置的預設情況下,它只開啟一級快取,一級快取只是相對於SqlSession而言,各個SqlSession是相互隔離的;
二級快取:SqlSessionFactory層面的二級快取是不開啟的,二級快取需要配置<cache/>元素,MyBatis要求返回的POJO是可序列化的,
也就是實現Serializable介面。
<cache eviction="LRU" flushInterval="100000" size="1024" readOnly=true"/>
eviction:快取回收策略
flushInterva:重新整理間隔時間
size:引用數目
readyOnly:只讀,意味著快取資料只能讀取不能修改
自定義快取:
在大型伺服器上,會使用各類不同的快取伺服器,這個時候我們可以定製快取,比如現在流行的redis快取,我們需要實現,org.apache.ibatis.cache.Cache
根據不同的快取做不同的實現,做完實現後,再配置
<cache type="com.kang.MyCache">
<property name="host" value="localhost"/> <!--可以配置一些快取中常用的屬性 -->
</cache>
在MyCache增加setHost方法,初始化的時候,會被呼叫到,這樣就可以對自定義設定一些外部引數
我們也可以配置SQL層面的快取機制,來決定它們是否需要使用或者重新整理快取,根據useCache和flushCache兩個屬性來完成,useCache標誌是否使用,
flushCache標誌插入後是否需要重新整理