天天看點

Mapper.xml映射器續(學習筆記)

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開發

繼續閱讀