7、resultMap配置
7.1、元素組成
<resultMap>
<constructor>
<idArg/>
<arg/>
</constructor>
<id/> //**
<result/> //**
<association/>
<collection/>
<discriminator>
<case/>
</discriminator>
</resultMap>
7.1.1、constructor元素用于配置構造方法。POJO類可能不存在沒有參數的構造方法
假設構造方法為:
public Role(int id,String roleName);
constructor元素配置為:
<constructor >
<idArg column="id" javaType="int"/>
<arg column="r_name" javaType="string"/>
</constructor>
這樣Mybatis就會使用對應構造方法來構造
7.1.2、id元素表示那個列是主鍵,允許多個主鍵(聯合主鍵)
7.1.3、result配置POJO到SQL的映射關系,result和idArg元素屬性如下
property 對應POJO的字段
column 對應SQL的列
javaType 類全名或别名
jdbcType
typeHandler 類型轉換器
7.1.4、其他的在7.3節詳述
7.2、存儲結果集
7.2.1、map存儲,resultType="map"
可讀性下降,需要進一步了解map鍵值的構成和資料類型
7.2.2、POJO存儲
之前也示例過,就不贅述了
7.3、級聯(示例是書上的,不想搬代碼了..把重點描述一下.....)
7.3.1、association元素,一對一級聯,property屬性代表映射到POJO屬性上,select配置為命名空間+SQL id ,指向對應Mapper的SQL,這樣就會将對應資料查詢回來,column代表SQL的列,用作參數傳遞給select屬性指定的SQL,多個參數需要用逗号隔開。
7.3.2、collection元素,一對多級聯,屬性基本同上
7.3.3、discriminator元素,鑒别器,屬性column代表使用哪個字段進行鑒别,子元素case,用于區分,類似switch..case語句,resultMap屬性表示采用哪個resultMap去映射。
示例:雇員employee表中一對一關聯工牌workcard表,工牌表中存有外鍵emp_id對應雇員編号
又 一對多關聯雇員任務employeeTask表,雇員任務表存有外鍵emp_id對應雇員編号,一個雇員有很多任務(雇員任務表中也有一對一關聯了任務Task表)
又 體檢表分男女(前列腺|子宮。。。等差別),又分男雇員和女雇員,提取相同點為Employee.java. 将不同屬性即體檢表放入子類。男雇員類MaleEmployee.java有一個男體檢表類型(MaleHealthForm.java)的屬性。女的類似。
在查詢雇員資訊時,将以上鎖關聯的資訊查詢出來,resultMap如下配置
<resultMap type="com.ssm.pojo.Employee" id="employee">
<id column="id" property="id"/>
<result column="real_name" property="realName"/>
<result column="sex" property="sex" typeHandler="com.ssm.handler.SexTypeHandler"/>
<result......../>
<association property="workCard" column="id"
select="com.ssm.mapper.WorkCardMapper.getWorkCardByEmpId"/>
<collection property="employeeTaskList" column="id"
select="com.ssm.mapper.EmployeeTaskMapper.getEmployeeTashByEmpId"/>
<discriminator javaType="long" column="sex">
<case value="1" resultMap="maleHealthFormMapper"/>
<case value="2" resultMap="femaleHealthFormMapper"/>
</discriminator>
</resultMap>
<resultMap type="com.ssm.pojo.FemaleEmployee"
id="femaleHealthFormMapper" extends="employee">
<association property="femaleHealthForm" column="id"
select="com.ssm.mapper.FemaleHealthFormMapper.getFemaleHealthForm"/>
</resultMap>
<resultMap type="com.ssm.pojo.MaleEmployee"
id="maleHealthFormMapper" extends="employee">
<association property="maleHealthForm" column="id"
select="com.ssm.mapper.MaleHealthFormMapper.getMaleHealthForm"/>
</resultMap>
7.3.4、延遲加載
之前介紹的Mybatis配置項setting中有兩個元素配置級聯lazyLoadingEnabled和aggressiveLazyLoading
lazyLoadingEnabled 延遲加載開關 預設關閉
aggressiveLazyLoading 啟動時,對任意屬性的調用會使帶有延遲加載屬性的對象完整加載 預設3.4.1(包含)前true,後false
前一個很好了解,後一個較為特殊
(例子我暫時沒有測試,過幾天吧)
-----将兩個都設定為true,調用上述的擷取雇員方法,發現雇員基本資訊和體檢表被查了出來,再次通路雇員對象的工牌屬性,發現雇員任務和工牌屬性都被查詢出來。但是雇員任務表中的一對一關聯屬性Task任務沒有查詢出來。
可以得出,aggressiveLazyLoading配置項是一個層級開關,設定為true,當通路級聯屬性時,鑒别器和實體是同一個層級,是以首先被加載,雇員任務和工卡是同一層級,故而一起被加載。
-----設定為true和false(按照上述前後順序),同樣查詢雇員,發現隻有雇員基本資訊被查詢出來
-----有時候會有特殊需求,在加載雇員過程中同時隻加載它的級聯屬性工卡
可以使用fetchType屬性,他可以處理上述全局配置無法解決的問題,隻出現在association和collection元素中
值有兩個:eager(獲得目前POJO對象後立即加載對應屬性) 和 lazy(延遲加載)
配置fetchType屬性會忽略上述兩個全局配置
7.3.5、另一種級聯
查詢雇員的SQL使用left join 将所有資訊在一條SQL中查詢出來,對應resultMap中也将對應關系一一映射。
這樣可以消除N+1問題(???)。會引發其他問題,SQL複雜,配置複雜,維護會有一定困難,這樣做法值得商榷。
7.3.6、多對多級聯
拆分為兩個一對多關系,例如角色表和使用者表的多對多,還有一個使用者角色表
示例RoleMapper.xml(大概):
<resultMap type="com.ssm.pojo.Role" id="roleMapper">
..............
<collection property ="userList" column="id" fetchType="lazy"
select="com.ssm.mapper.UserMapper.findUserByRoleId"/>
</resultMap>
<select id ="findRoleByUserId" parameterType="long" resultMap="roleMapper">
select r.id,r.role_name,r.note from role r,user_role ur
where r.id=ur.role_id and ur.user_id =#{userId}
</select>
UserMapper.xml也差不多吧,就不寫了吧
8、緩存
8.1、一級緩存和二級緩存
一級緩存在SqlSession上的緩存,二級緩存是在SqlSessionFactory上的緩存,預設情況下,Mybatis會開啟一級緩存,一級緩存不需要對象可序列化(實作Serializable),二級緩存需要
示例:在同一個SqlSession下,兩次相同的查詢隻會執行一次SQL,因為第一次擷取對象後會緩存起來,若緩存沒有逾時或者沒有聲明需要重新整理時,就會從緩存擷取資料,對不同的SqlSession不共享
RoleMapper roleMapper = SqlSession.getMapper(RoleMapper.class);
Role role = roleMapper.getRole(1);
logger.info("再擷取一次");
Role role1 = roleMapper.getRole(1);
為了使不同SqlSession之間共享緩存,需要開啟二級緩存,在RoleMapper.xml中加入如下代碼,需要對POJO對象實作序列化
<cache/>
8.2、緩存配置項、自定義、引用
加入上述cache元素後,Mybatis會将對應命名空間的所有select元素查詢結果進行緩存,而其中的insert,delete,update在操作時會重新整理緩存
8.2.1、緩存cache配置項
----blocking 是否使用阻塞性緩存,在讀寫時會加入JNI的鎖進行操作 預設false,可保證讀寫安全,但性能不佳
----readOnly 緩存内容是否隻讀 ,預設false ,若為隻讀,則不會造成多線程讀寫的不一緻
----eviction 緩存政策 分為:
1》LRU 最近最少使用:移除最長時間不被使用的對象
2》FIFO 先進先出:按對象進入緩存的順序移除
3》SOFT 軟引用:移除基于垃圾回收器狀态和軟引用規則的對象
4》WEAK弱引用:更積極移除基于垃圾收集器狀态和弱引用規則的對象
----flushInterval 重新整理時間,正數,機關毫秒,超過時間緩存失效,預設null,即沒有重新整理時間,旨在執行增删改語句時才重新整理
----type 自定義緩存類,需要實作接口org.apache.ibatis.cache.Cache
----sizze 緩存對象個數 正整數,預設1024
8.2.2、自定義
假設存在一個緩存實作類com.ssm.cache.RedisCache
配置如下:
<cache type="com.ssm.cache.RedisCache">
<property name="host" value="localhost"/>
</cache>
這樣配置後,Mybatis會啟用緩存,同時調用setHost(String host)方法,去設定配置内容。
對于一些查詢語句并不想要它進行緩存,可以配置:
<select ..... flushCache="false" useCache="true"/>
<insert ... flushCache="true"/>
<update ... flushCache="true"/>
<delete ... flushCache="true"/>
以上是預設配置,可以根據需要修改。flushCache代表是否重新整理緩存,useCache屬性是select特有的,代表是否使用緩存。
8.2.3、引用
上述都是在一個映射器RoleMapper.xml中使用,如果需要在其他映射器使用相同的配置,則可以引用緩存的配置
<cache-ref namespace="com.ssm.mapper.RoleMapper"/>
這樣就可以引用對于映射器的cache元素的配置了
Mapper中還支援存儲過程和動态SQL,另起一篇
--參考書目
JavaEE網際網路輕量級架構整合開發--SSM架構(Spring MVC +Spring+Mybatis)和Redis開發