mybatis學習筆記(15)-查詢緩存之二級緩存

mybatis學習筆記(15)-查詢緩存之二級緩存

標籤: mybatisjava


[TOC]mysql


本文主要講mybatis的二級緩存,二級緩存是mapper級別的緩存,多個SqlSession去操做同一個Mapper的sql語句,多個SqlSession能夠共用二級緩存,二級緩存是跨SqlSession的。git

二級緩存原理

二級緩存原理

首先開啓mybatis的二級緩存.github

sqlSession1去查詢用戶id爲1的用戶信息,查詢到用戶信息會將查詢數據存儲到二級緩存中。sql

若是SqlSession3去執行相同mapper下sql,執行commit提交,清空該mapper下的二級緩存區域的數據。數據庫

sqlSession2去查詢用戶id爲1的用戶信息,去緩存中找是否存在數據,若是存在直接從緩存中取出數據。緩存

二級緩存與一級緩存區別,二級緩存的範圍更大,多個sqlSession能夠共享一個UserMapper的二級緩存區域session

UserMapper有一個二級緩存區域(按namespace分),其它mapper也有本身的二級緩存區域(按namespace分)。每個namespace的mapper都有一個二緩存區域,兩個mapper的namespace若是相同,這兩個mapper執行sql查詢到數據將存在相同的二級緩存區域中。mybatis

開啓二級緩存

mybaits的二級緩存是mapper範圍級別,除了在SqlMapConfig.xml設置二級緩存的總開關,還要在具體的mapper.xml中開啓二級緩存。app

在覈心配置文件SqlMapConfig.xml中加入<setting name="cacheEnabled" value="true"/>

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

在UserMapper.xml中開啓二緩存,UserMapper.xml下的sql執行完成會存儲到它的緩存區域(HashMap)。

<mapper namespace="com.iot.mybatis.mapper.UserMapper">
<!-- 開啓本mapper的namespace下的二級緩存-->
<cache />

...

</mapper>

調用pojo類實現序列化接口

public class User implements Serializable{
    ....
}

爲了將緩存數據取出執行反序列化操做,由於二級緩存數據存儲介質多種多樣,不必定在內存。

測試方法

// 二級緩存測試
@Test
public void testCache2() throws Exception {
	SqlSession sqlSession1 = sqlSessionFactory.openSession();
	SqlSession sqlSession2 = sqlSessionFactory.openSession();
	SqlSession sqlSession3 = sqlSessionFactory.openSession();
	// 建立代理對象
	UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
	// 第一次發起請求,查詢id爲1的用戶
	User user1 = userMapper1.findUserById(1);
	System.out.println(user1);

	//這裏執行關閉操做,將sqlsession中的數據寫到二級緩存區域
	sqlSession1.close();


//		//使用sqlSession3執行commit()操做
//		UserMapper userMapper3 = sqlSession3.getMapper(UserMapper.class);
//		User user  = userMapper3.findUserById(1);
//		user.setUsername("張明明");
//		userMapper3.updateUser(user);
//		//執行提交,清空UserMapper下邊的二級緩存
//		sqlSession3.commit();
//		sqlSession3.close();



	UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
	// 第二次發起請求,查詢id爲1的用戶
	User user2 = userMapper2.findUserById(1);
	System.out.println(user2);

	sqlSession2.close();
}

1.無更新,輸出

DEBUG [main] - Cache Hit Ratio [com.iot.mybatis.mapper.UserMapper]: 0.0
DEBUG [main] - Opening JDBC Connection
DEBUG [main] - Created connection 103887628.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@631330c]
DEBUG [main] - ==>  Preparing: SELECT * FROM user WHERE id=? 
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <==      Total: 1
User [id=1, username=測試用戶22, sex=2, birthday=null, address=null]
DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@631330c]
DEBUG [main] - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@631330c]
DEBUG [main] - Returned connection 103887628 to pool.
DEBUG [main] - Cache Hit Ratio [com.iot.mybatis.mapper.UserMapper]: 0.5
User [id=1, username=測試用戶22, sex=2, birthday=null, address=null]

2.有更新,輸出

DEBUG [main] - Cache Hit Ratio [com.iot.mybatis.mapper.UserMapper]: 0.0
DEBUG [main] - Opening JDBC Connection
DEBUG [main] - Created connection 103887628.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@631330c]
DEBUG [main] - ==>  Preparing: SELECT * FROM user WHERE id=? 
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <==      Total: 1
User [id=1, username=測試用戶22, sex=2, birthday=null, address=null]
DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@631330c]
DEBUG [main] - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@631330c]
DEBUG [main] - Returned connection 103887628 to pool.
DEBUG [main] - Cache Hit Ratio [com.iot.mybatis.mapper.UserMapper]: 0.5
DEBUG [main] - Opening JDBC Connection
DEBUG [main] - Checked out connection 103887628 from pool.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@631330c]
DEBUG [main] - ==>  Preparing: update user set username=?,birthday=?,sex=?,address=? where id=? 
DEBUG [main] - ==> Parameters: 張明明(String), null, 2(String), null, 1(Integer)
DEBUG [main] - <==    Updates: 1
DEBUG [main] - Committing JDBC Connection [com.mysql.jdbc.JDBC4Connection@631330c]
DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@631330c]
DEBUG [main] - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@631330c]
DEBUG [main] - Returned connection 103887628 to pool.
DEBUG [main] - Cache Hit Ratio [com.iot.mybatis.mapper.UserMapper]: 0.3333333333333333
DEBUG [main] - Opening JDBC Connection
DEBUG [main] - Checked out connection 103887628 from pool.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@631330c]
DEBUG [main] - ==>  Preparing: SELECT * FROM user WHERE id=? 
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <==      Total: 1
User [id=1, username=張明明, sex=2, birthday=null, address=null]
DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@631330c]
DEBUG [main] - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@631330c]
DEBUG [main] - Returned connection 103887628 to pool.

useCache配置

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

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

總結:針對每次查詢都須要最新的數據sql,要設置成useCache=false,禁用二級緩存。

刷新緩存(就是清空緩存)

刷新緩存就是清空緩存。在mapper的同一個namespace中,若是有其它insert、update、delete操做數據後須要刷新緩存,若是不執行刷新緩存會出現髒讀。

設置statement配置中的flushCache="true"屬性,默認狀況下爲true即刷新緩存,若是改爲false則不會刷新。使用緩存時若是手動修改數據庫表中的查詢數據會出現髒讀。以下:

<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User" flushCache="true">

總結:通常下執行完commit操做都須要刷新緩存,flushCache=true表示刷新緩存,這樣能夠避免數據庫髒讀。

應用場景和侷限性

  • 應用場景

對於訪問多的查詢請求且用戶對查詢結果實時性要求不高,此時可採用mybatis二級緩存技術下降數據庫訪問量,提升訪問速度,業務場景好比:耗時較高的統計分析sql、電話帳單查詢sql等。

實現方法以下:經過設置刷新間隔時間,由mybatis每隔一段時間自動清空緩存,根據數據變化頻率設置緩存刷新間隔flushInterval,好比設置爲30分鐘、60分鐘、24小時等,根據需求而定。

  • 侷限性

mybatis二級緩存對細粒度的數據級別的緩存實現很差,好比以下需求:對商品信息進行緩存,因爲商品信息查詢訪問量大,可是要求用戶每次都能查詢最新的商品信息,此時若是使用mybatis的二級緩存就沒法實現當一個商品變化時只刷新該商品的緩存信息而不刷新其它商品的信息,由於mybaits的二級緩存區域以mapper爲單位劃分,當一個商品信息變化會將全部商品信息的緩存數據所有清空。解決此類問題須要在業務層根據需求對數據有針對性緩存。


做者@brianway更多文章:我的網站 | CSDN | oschina

相關文章
相關標籤/搜索