Mybatis經常使用用法之 Mybatis緩存

這是我參與更文挑戰的第2天,活動詳情查看: 更文挑戰web

一:定義

緩存就是內存中的數據,經常來自對數據庫查詢結果的保存,使用緩存,咱們能夠避免頻繁的與數據庫 進行交互,進而提升響應速度redis

Mybatis也支持數據的緩存,分爲一級緩存和二級緩存,能夠經過下圖理解一級緩存和二級緩存的做用範圍:sql

image.png

以上能夠看出數據庫

  1. 一級緩存是sqlsession級別的緩存,直白的說就是單個sql語句的緩存,在操做數據庫時,須要構建sqlsession對象,在對象中有一個數據結構(HashMap)用戶存儲緩存數據,不一樣的sqlsession之間的緩存互不影響
  2. 二級緩存是Mapper級別的緩存,直白的說就是一個xml文件的緩存,該緩存默認是關閉的,多個sqlsession去操做同一個Mapper中的SQL語句,共用一個緩存,該緩存是跨sqlsession的

二:一級緩存

當咱們進行sql查詢的時候,Mybatis會先到緩存中去查詢該sql語句的緩存,若是該緩存已經存在,則直接返回緩存中的結果,再也不進行數據庫交互,當緩存中不存在該sql語句的緩存的時候,則會直接去數據庫查詢,獲取結果後,會將結果進行緩存,並同時發送給用戶 當用戶執行commit操做(插入,刪除,更新),則會清空sqlsession的一級緩存,目的是爲了不出現髒讀。緩存

三:二級緩存

二級緩存和一級緩存原理同樣,第一次查詢會將數據放入緩存,後續查詢會從緩存中取,可是一級緩存是sqlsession級別,二級緩存是mapper級別的,也就是說,多個sqlsession能夠共享一個mapper中的二級緩存,若是兩個mapper的namespace相同,即便是不一樣文件的兩個mapper,他們執行sql查詢到的數據也維護在同一個二級緩存中。服務器

image.png

四:如何使用二級緩存

因爲二級緩存默認是關閉的,因此須要咱們手動開啓 1.首先,咱們須要在全局配置文件sqlMapConfig.xml文件中加入以下代碼:markdown

<!--開啓二級緩存--> 
<settings> <setting name="cacheEnabled" value="true"/> </settings>
複製代碼

而後再具體的Mapper.xml中開啓緩存,添加以下配置session

<cache></cache>
複製代碼

咱們能夠看到mapper.xml文件中就這麼一個空標籤,其實這裏能夠配置,PerpetualCache這個類是 mybatis默認實現緩存功能的類。咱們不寫type就使用mybatis默認的緩存,也能夠去實現Cache接口 來 自定義緩存。數據結構

開啓了二級緩存後,還須要將要緩存的pojo實現Serializable接口,爲了將緩存數據取出執行反序列化操 做,由於二級緩存數據存儲介質多種多樣,不必定只存在內存中,有可能存在硬盤中,若是咱們要再取 這個緩存的話,就須要反序列化了。因此mybatis中的pojo都去實現Serializable接口mybatis

mybatis中還能夠配置userCacheflushCache等配置項,userCache是用來設置是否禁用二級緩 存 的,在statement中設置useCache=false能夠禁用當前select語句的二級緩存,即每次查詢都會發出 sql 去查詢,默認狀況是true,即該sql使用二級緩存

<select id="selectUserByUserId" useCache="false" resultType="com.pojo.User" parameterType="int"> 
    select * from user where id=#{id} 
</select>
複製代碼

這種狀況是針對每次查詢都須要最新的數據sql,要設置成useCache=false,禁用二級緩存,直接從數 據 庫中獲取。 在mapper的同一個namespace中,若是有其它insert、update, delete操做數據後須要刷新緩存,如 果不執行刷新緩存會出現髒讀。 設置statement配置中的flushCache="true」屬性,默認狀況下爲true,即刷新緩存,若是改爲false則 不 會刷新。使用緩存時若是手動修改數據庫表中的查詢數據會出現髒讀。

<select id="selectUserByUserId" flushCache="true" useCache="false" resultType="com.pojo.User" parameterType="int"> 
    select * from user where id=#{id} 
</select>
複製代碼

通常下執行完commit操做都須要刷新緩存,flushCache=true表示刷新緩存,這樣能夠避免數據庫髒 讀。因此咱們不用設置,默認便可

五:二級緩存整和redis

上面咱們介紹了 mybatis自帶的二級緩存,可是這個緩存是單服務器工做,沒法實現分佈式緩存。 那麼 什麼是分佈式緩存呢?通常分佈式項目同一個服務都會部署多個,若是咱們用mybatis默認的緩存,用戶第一次訪問的時候根據負載均衡可能會訪問到服務器A,當繼續第二次訪問的時候,可能就會訪問到服務器B,那麼原先在服務器A上的緩存,咱們是拿不到的,因此進行第二次訪問的時候,仍是須要直接訪問數據庫,這樣就違背了咱們用緩存存儲的初衷,效果以下圖所示:

image.png

爲了解決這個問題,就得找一個分佈式的緩存,專門用來存儲緩存數據的,這樣不一樣的服務器要緩存數 據都往它那裏存,取緩存數據也從它那裏取,以下圖所示:

image.png

如上圖所示,在幾個不一樣的服務器之間,咱們使用第三方緩存框架,將緩存都放在這個第三方框架中, 然 後不管有多少臺服務器,咱們都能從緩存中獲取數據。 這裏咱們介紹mybatis與redis的整合。

實現: pom文件:

<dependency> 
    <groupId>org.mybatis.caches</groupId> 
    <artifactId>mybatis-redis</artifactId> 
    <version>1.0.0-beta2</version> 
</dependency>
複製代碼

配置文件:

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.mapper.IUserMapper"> <cache type="org.mybatis.caches.redis.RedisCache" /> <select id="findAll" resultType="com.pojo.User" useCache="true"> select * from user </select> 複製代碼

redis.properties:

redis.host=localhost 
redis.port=6379 
redis.connectionTimeout=5000 
redis.password= 
redis.database=0
複製代碼

注意:這裏的redis.properties爲固定文件名稱,不可變

爲何要名稱固定爲這個呢?接下來咱們翻閱一下源碼,找尋一下答案.

RedisCache和你們廣泛實現Mybatis的緩存方案大同小異,無非是實現Cache接口,並使用jedis操做緩 存;

image.png

RedisCache在mybatis啓動的時候,由MyBatis的CacheBuilder建立,建立的方式很簡單,就是調用 RedisCache的帶有String參數的構造方法,即RedisCache(String id);而在RedisCache的構造方法中, 調用了 RedisConfigu rationBuilder 來建立 RedisConfig 對象,並使用 RedisConfig 來建立JedisPool。 接下來咱們進入 parseConfiguration()方法中繼續分析。

image.png 咱們能夠看到 在該方法的第一行就更加一個路徑,調用getResourceAsStream()方法,將文件加載爲IO流, 顯而易見,咱們的配置文件路徑確定就是代碼中對應的redisPropertiesFilename屬性

咱們在看一下redisPropertiesFilename屬性對應的是什麼值

image.png 咱們看到 實際redisPropertiesFilename並無指定什麼值,再往下看,咱們看到一個構造函數,在該構造函數中,咱們發現,redisPropertiesFilename其實就是上面常量中所對應的值,而常量對應的值就是咱們的 redis.properties,由此能夠得出上面的結論。

本篇文章到此結束,但願對各位小夥伴有所幫助

相關文章
相關標籤/搜索