MyBatis 之 緩存

MyBatis 和 Hibernate 同樣具備 一級緩存二級緩存java

1.  一級緩存:MyBatis 一級緩存的做用域 是 同一個SqlSessionsql

    寫一個 查詢 User 的例子:數據庫

  <!-- user 查詢 -->
  <select id="findUserById" parameterType="int" resultType="user">
  	select * from users where userId = #{user_id}
  </select>
//測試一級緩存
@Test
public void testCache1() throws Exception {
	//獲取SqlSession
	SqlSession sqlSession = sqlSessionFactory.openSession();
		
	OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
		
	//第一次查詢
	User user = new User();
	user.setUserId(100108);
		
	System.out.println("-----------------第一次查詢,從數據庫獲取--------------------");
	User getUser = orderMapper.findUserById(user.getUserId());
	System.out.println(getUser);
		
	System.out.println("-----------------第二次查詢,從緩存中獲取--------------------");
		
	//再次執行一樣的查詢
	User getUser2 = orderMapper.findUserById(user.getUserId());
	System.out.println(getUser2);
}

    執行結果:
api

    

    從結果中能夠看出:第一次查詢,在數據庫中執行了 SQL。 而第二次並無經過查詢數據庫獲得結果,緩存

    而是從緩存中獲取的。那麼緩存的機制是什麼樣的?安全

    SqlSession 緩存機制:執行一個SQL的時候,MyBatis 會首先去 緩存(PerpetualCache)中 根據 key 查詢session

    結果集,a. 若是沒有則去查詢數據庫,查詢成功後,將結果寫入 cache 中;b. 若是有,則直接從緩存中mybatis

    取出結果集返回。app

    MyBatis 內部存儲 緩存使用的是一個 HashMap<CacheKey , Object>, key 爲 hashCode + sqlId 框架

    + Sql語句的格式, value 則是查詢出來映射生成的 Java 對象。

    問題:若是在第二次查詢以前,更新了這個 User 的信息,那麼第二次查詢是從緩存中取出數據仍是再查詢一次?

        結果是顯而易見的,在 更新、刪除操做的時,cache 會被清空。因此會再查詢一次。

2.  二級緩存:即查詢緩存,它的做用域是一個 mapper 的namespace,即在同一個 namespace 中的查詢sql

     能夠從緩存中獲取數據。二級緩存是能夠跨 SqlSession 的。

    a. 開啓二級緩存:在SqlMapConfig.xml 的 <settings>...</settings>中加入

<!-- 開啓二級緩存 -->
<setting name="cacheEnabled" value="true"/>
  屬性名   描述   容許值   默認值
cacheEnabled   對在此配置文件下全部的 cache 進行全局性開/關設置   true / false   true

    b. 在 mapper.xml 文件中添加 <cache /> 開啓緩存

<mapper namespace="mybatis_b.mapper.OrderMapper">
  <!-- 開啓本 mapper 的二級緩存 -->
  <cache />
</mapper>

    c. Java 調用,這裏用兩個 SqlSession 來實現二級緩存的跨 SqlSession

//測試二級緩存
@Test
public void testCache2() throws Exception {
	//獲取SqlSession
	SqlSession sqlSession = sqlSessionFactory.openSession();		
	OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
		
	SqlSession sqlSession2 = sqlSessionFactory.openSession();
        OrderMapper orderMapper2 = sqlSession2.getMapper(OrderMapper.class);
		
	//第一次查詢
	User user = new User();
	user.setUserId(100108);
		
	System.out.println("-----------------第一次查詢,從數據庫獲取--------------------");
	User getUser = orderMapper.findUserById(user.getUserId());
	System.out.println(getUser);
		
	//關閉session1
	sqlSession.close();
		
	System.out.println("-----------------第二次查詢,從緩存中獲取--------------------");
		
	//再次執行一樣的查詢
	User getUser2 = orderMapper2.findUserById(user.getUserId());
	System.out.println(getUser2);
	sqlSession2.close();
}

    其中,User 類要實現序列化接口。執行後發現第二次的確是從緩存中獲取數據的,結果就不貼了。

    問題:若是在 第一次查詢完後,更新某個數據,那麼第二次還會從緩存中獲取數據嗎?結果是不是最新?

    結果:第二次依舊是從緩存中獲取的,並且是最新的。由於:在 mapper 的同一個 namespace 中,若是有

              其餘 insert、update、delete 操做數據後須要刷新緩存,若是不執行則會出現髒讀。而 mapper

              的sql 中有 flushCache="true" 這個屬性,默認爲 true即刷新 mapper 級別的緩存。

3. Cache 的其餘參數:

    flushInterval:刷新間隔,能夠設置爲任意的正整數,表示一個合理的時間段,以毫秒爲單位。默認狀況是

                            不設置,也就是沒有刷新間隔,僅在調用語句時刷新緩存。

    size:引用數目,能夠設置爲任意的正整數,要記住你緩存的對象和 運行環境的可用內存資源,默認值是1024

    readOnly:只讀屬性。只讀的緩存會給全部的調用者返回緩存對象相同的實例。所以這些對象不能被修改。

                       這提供了很重要的性能優點。可讀寫的緩存會返回緩存對象的拷貝(經過序列化)。這會慢一些

                      ,可是安全,所以默認是false。

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

    上面這個緩存配置建立了一個FIFO緩存,並每隔60s刷新,存儲結果對象或列表的512個引用,並且返回的

    對象被認爲是隻讀的,所以在不一樣的線程中調用者之間修改它們會致使衝突。

    可用的回收策略有:

    A. LRU - 最近最少使用的:移除最長時間不被使用的對象

    B. FIFO - 先進先出:按對象進入緩存的順序來移除它們。

    C. SOFT - 軟引用:移除基於垃圾回收器狀態和軟引用規則的對象。

    D. WEAK - 弱引用:更積極地移除基於垃圾回收器狀態和軟引用規則的對象。

4. MyBatis 與 緩存框架 eacache 進行了整合,採用 eacache 框架管理緩存數據。

    a. 引入緩存的依賴包,須要 mybatis-ehcache-1.0.3.jar   ehcache-core-2.6.8.jar  和 slf4j-api-1.6.1.jar

    b. 修改 mapper 的緩存配置:

<!-- 如下兩個<cache>標籤二選一,第一個能夠輸出日誌,第二個不輸出日誌 -->
<cache type="org.mybatis.caches.ehcache.LoggingEhcache" />
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

    有待詳解。。。

相關文章
相關標籤/搜索