MyBatis學習(六)---高級應用(延遲加載、緩存)

MyBatis學習(六)—高級應用(延遲加載、緩存)

標籤(空格分隔): MyBatis學習


延遲加載

需要查詢關聯信息時,使用mybatis延遲加載特性可有效的減少數據庫壓力,首次查詢只查詢主要信息,關聯信息等用戶獲取時再加載.

開啓延遲加載
在mybatis的全局配置文件中,需要開啓延遲加載功能

<settings>
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="aggressiveLazyLoading" value="false"/>
</settings>

lazyLoadingEnabled:默認值false,全局性設置懶加載。如果設爲‘false’,則所有相關聯的都會被初始化加載。
aggressiveLazyLoading:默認值true,當設置爲‘true’的時候,懶加載的對象可能被任何懶屬性全部加載。否則,每個屬性都按需加載

一對一查詢懶加載實現

1、po對象的設置和一對一映射的一致,也就是在po對象中設置一個屬性爲關聯查詢得對象
2、mapper.xml中的配置
2.1 設置一個查詢

<select id="findOrdersList3" resultMap="userordermap2">
    SELECT
    orders.*
    FROM
    orders
</select>

2.2 關聯查詢

<!-- 訂單信息resultmap -->
<resultMap type="Orders" id="userordermap2">
<id property="id" column="id"/>
<result property="user_id" column="user_id"/>
<result property="number" column="number"/>
<association property="user" javaType="User" select="findUserById" column="user_id"/>
</resultMap>

association:
select=”findUserById”:指定關聯查詢sql爲findUserById
column=”user_id”:關聯查詢時將users_id列的值傳入findUserById

當對象中需要使用的user屬性時,纔會發起關聯查詢。

一對多查詢懶加載實現

一對多延遲加載的方法同一對一延遲加載,在collection標籤中配置select內容

和一對一懶加載類似

小結

如果說不使用MyBatis的關聯查詢,怎麼實現懶加載

其實很簡單,定義兩個不同的查詢statementid。通過java的遍歷,當需要用到關聯的屬性的時候,發起一個數據庫查詢操作

作用:

當需要查詢關聯信息時再去數據庫查詢,默認不去關聯查詢,提高數據庫性能。
只有使用resultMap支持延遲加載設置。

緩存

Mybatis的查詢緩存分一級緩存和二級緩存兩種。Mybatis內部存儲緩存使用一個HashMap,key爲hashCode+sqlId+Sql語句。value爲從查詢出來映射生成的java對象

一級緩存

一級緩存的生命週期是一個SqlSession,當同一個SqlSession中兩次執行相同的sql,輸入參數也相同時,SqlSession在查詢第一次的時候會將查詢的結果保存到緩存的一個Map結構中,當第二次發起查詢時,先默認到緩存中獲取。SqlSession結束後,該緩存中的數據也隨之被清空,MyBatis默認開啓一級緩存
這裏寫圖片描述

二級緩存

二級緩存是多個SqlSession共享的,作用域是mapper的同一個namespace中,不同的SqlSession兩次執行同一個namespace下的sql,當查詢完之後,會將結果緩存起來,第二次執行查詢時,先查詢該namespace下是否有緩存數據,有則直接返回,但爲了保證沒有髒讀,SqlSession執行insert、update、delete操作之後,會清空二級緩存,MyBatis默認不開啓二級緩存。
這裏寫圖片描述

注意:二級緩存需要查詢結果映射的pojo對象實現java.io.Serializable接口實現序列化和反序列化操作,注意如果存在父類、成員pojo都需要實現序列化接口

開啓二級緩存

在覈心配置文件SqlMapConfig.xml中加入

<setting name="cacheEnabled" value="true"/>

同時需要在mapper.xml中添加一個,表示namespace開啓二級緩存

 <cache /> 

其中可以設置該緩存的刷新規則。例如如下配置:

<cache  eviction="FIFO"  flushInterval="60000"  size="512"  readOnly="true"/>

flushInterval(刷新間隔)可以被設置爲任意的正整數,而且它們代表一個合理的毫秒形式的時間段。默認情況是不設置,也就是沒有刷新間隔,緩存僅僅調用語句時刷新。
size(引用數目)可以被設置爲任意正整數,要記住你緩存的對象數目和你運行環境的可用內存資源數目。默認值是1024。
readOnly(只讀)屬性可以被設置爲true或false。只讀的緩存會給所有調用者返回緩存對象的相同實例。因此這些對象不能被修改。這提供了很重要的性能優勢。可讀寫的緩存會返回緩存對象的拷貝(通過序列化)。這會慢一些,但是安全,因此默認是false
這個更高級的配置創建了一個 FIFO 緩存,並每隔 60 秒刷新,存數結果對象或列表的 512 個引用,而且返回的對象被認爲是隻讀的,因此在不同線程中的調用者之間修改它們會導致衝突。可用的收回策略有, 默認的是 LRU:
1. LRU – 最近最少使用的:移除最長時間不被使用的對象。
2. FIFO – 先進先出:按對象進入緩存的順序來移除它們。
3. SOFT – 軟引用:移除基於垃圾回收器狀態和軟引用規則的對象。
4. WEAK – 弱引用:更積極地移除基於垃圾收集器狀態和弱引用規則的對象

禁用二級緩存

在statement中設置useCache=false可以禁用當前select語句的二級緩存,即每次查詢都會發出sql去查詢,默認情況是true,即該sql使用二級緩存

<select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">

刷新緩存

在mapper的同一個namespace中,如果有其它insert、update、delete操作數據後需要刷新緩存,如果不執行刷新緩存會出現髒讀.(手動修改數據庫數據也會出現髒讀)
如果不想執行完sql後清空緩存,可以在statement 中設置flushCache=”true”。

<insert id="insertUser" parameterType="user" flushCache="true">

mybatis和第三方緩存整合

我們系統爲了提高系統併發,性能、一般對系統進行分佈式部署(集羣部署方式)。不使用分佈緩存,緩存的數據在各各服務單獨存儲,不方便系統開發。所以要使用分佈式緩存對緩存數據進行集中管理。
mybatis無法實現分佈式緩存,需要和其它分佈式緩存框架進行整合。
這裏寫圖片描述

總結

應用場景

對於訪問多的查詢請求且用戶對查詢結果實時性要求不高,此時可採用mybatis二級緩存技術降低數據庫訪問量,提高訪問速度,業務場景比如:耗時較高的統計分析sql、電話賬單查詢sql等。
實現方法如下:通過設置刷新間隔時間,由mybatis每隔一段時間自動清空緩存,根據數據變化頻率設置緩存刷新間隔flushInterval,比如設置爲30分鐘、60分鐘、24小時等,根據需求而定

侷限性

mybatis二級緩存對細粒度的數據級別的緩存實現不好。當數據庫中某一個數據的變更會清空整個域的緩存。解決此類問題需要在業務層根據需求對數據有針對性緩存,通過手動的將數據添加到第三方緩存中

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章