mybatis緩存管理

緩存的作用

mybatis緩存機制用於提高數據庫性能,減輕數據壓力。

緩存作用域

一級緩存是sqlsession級別的,就是每個sqlsession裏都有一個HashMap來存儲數據,當然不同對象每個緩存區域也不一樣,所以一級緩存是不相互影響的。

二級緩存是mapper級別的的,也就是每個sqlsession都可以訪問同一個mapper,這裏不是說二級緩存只有一個,也是每個mapper中有一個,就比如UserMapper,TestMapper,當然前提是這兩個mapper的namespace是不樣的(一般每個mapper都是不一樣的),因爲真正區別二級緩存的是namespace,也就是每個namespace對應一個獨一無二的二級緩存,這裏二級緩存的存儲也就是HashMap。


mybatis緩存機制

首先一級緩存默認是開啓的,一級緩存是sqllsession級別的緩存,sqlsession對象中有一個數據結構HashMap用於存儲緩存數據, 不同的sqlsession之間的一級緩存不相互影響的。

二級緩存也是默認開啓的,對於每個sqlsession如果查詢的是同一個mapper(namespace)都可以從同一個二級緩存中讀取。

mybatis緩存特性

當用戶進行查詢的時候,mybatis提供緩存機制可以將數據存儲下來,一遍之後在次查詢的時候可以直接從緩存中讀取,而不用再次查詢數據庫,mybatis存儲方式HashMap,一級緩存對應的是mapper中的sql的id爲key來存儲緩存數據,首先當發起請求查詢數據庫的時候會先產看二級緩存是否開啓,如果開啓會從二級緩存中查看,如果沒有開啓會先從mybatis一級中的緩存(HashMap)中去查詢,如果不存在那麼將會執行sql語句,再將數據存入緩存。當執行更新,刪除,插入的時候緩存中的數據將會被清空,清空的目的也就是爲了避免從緩存中的讀取髒數據,也就是保證緩存中的數據都是最新的數據。

一級緩存代碼測試

代碼環境是一個spring,mybatis的環境
測試代碼1

@Test
	public void OneCacheTest(){
	    ApplicationContext ac = new FileSystemXmlApplicationContext("classpath:spring-context-dao.xml"); 
		SqlSessionFactory sqlSessionFactory = (SqlSessionFactory) ac.getBean("sqlSessionFactory");
		SqlSession sqlSession = sqlSessionFactory.openSession();
		userMapper mapper = sqlSession.getMapper(userMapper.class);
		User user1 = mapper.finduserbyusername("3");
		System.out.println(user1);
		User user2 = mapper.finduserbyusername("3");
		sqlSession.close();
		System.out.println(user2);
	}

結果

20:01:30,003 DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger debug:139 -> ==>  Preparing: select username,password,permission from user where username=?; 
20:01:30,050 DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger debug:139 -> ==> Parameters: 3(String)
20:01:30,072 DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger debug:139 -> <==      Total: 1
20:01:30,072 DEBUG org.springframework.jdbc.datasource.DataSourceUtils doReleaseConnection:327 -> Returning JDBC Connection to DataSource
User [username=3, password=3, permission=]
20:26:34,557 DEBUG org.springframework.jdbc.datasource.DataSourceUtils doReleaseConnection:327 -> Returning JDBC Connection to DataSource
User [username=3, password=3, permission=]
都上結果可以看出這發出了一條sql,第二次沒發出sql語句,而是直接從緩存中讀取了數據,就是因爲這裏是同一個sqlsession發起的。


測試代碼2

@Test
	public void OneCacheTest(){
	    ApplicationContext ac = new FileSystemXmlApplicationContext("classpath:spring-context-dao.xml"); 
		SqlSessionFactory sqlSessionFactory = (SqlSessionFactory) ac.getBean("sqlSessionFactory");
		SqlSession sqlSession = sqlSessionFactory.openSession();
		userMapper mapper = sqlSession.getMapper(userMapper.class);
		User user1 = mapper.finduserbyusername("3");
		System.out.println(user1);
		mapper.updateuser(new User("3", "3", ""));
		User user2 = mapper.finduserbyusername("3");
		sqlSession.close();
		System.out.println(user2);
	}
結果

20:29:50,018 DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger debug:139 -> ==>  Preparing: select username,password,permission from user where username=?; 
20:29:50,061 DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger debug:139 -> ==> Parameters: 3(String)
20:29:50,082 DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger debug:139 -> <==      Total: 1
User [username=3, password=3, permission=]
20:29:50,083 DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger debug:139 -> ==>  Preparing: update user set password = ?, permission = ? where username = ? 
20:29:50,084 DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger debug:139 -> ==> Parameters: 3(String), (String), 3(String)
20:29:50,126 DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger debug:139 -> <==    Updates: 1
20:29:50,127 DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger debug:139 -> ==>  Preparing: select username,password,permission from user where username=?; 
20:29:50,128 DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger debug:139 -> ==> Parameters: 3(String)
20:29:50,131 DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger debug:139 -> <==      Total: 1
20:29:50,133 DEBUG org.springframework.jdbc.datasource.DataSourceUtils doReleaseConnection:327 -> Returning JDBC Connection to DataSource
User [username=3, password=3, permission=]
這裏和上面結果截然不同,這裏發起的3條sql原因就是執行更新,刪除,添加語句會清空緩存。

二級緩存的配置

二級緩存和一級緩存不一樣,一級緩存是默認配置的,二級緩存可以根據自己情況了來配置。

pojo類需要實現序列化接口

public class User implements Serializable

mybatis配置文件的配置

<!-- 全局配置參數 -->
	<settings>
		<!-- 打開延遲加載開關 -->
		<setting name="lazyLoadingEnabled" value="true"/>
		<!-- 關閉積極加載,就是按需加載 -->
		<setting name="aggressiveLazyLoading" value="false"/>
		<!-- 開啓二級緩存 -->
		<setting name="cacheEnabled" value="true"/>
	</settings>

這裏二級緩存也是默認開啓,也就是cacheEnabled默認true。

UserMapper文件配置

<cache/>
只用加這一個就可以使用了。

二級緩存測試代碼


這裏代碼和上代碼一樣。

@Test
	public void OneCacheTest(){
	    ApplicationContext ac = new FileSystemXmlApplicationContext("classpath:spring-context-dao.xml"); 
		SqlSessionFactory sqlSessionFactory = (SqlSessionFactory) ac.getBean("sqlSessionFactory");
		SqlSession sqlSession = sqlSessionFactory.openSession();
		userMapper mapper = sqlSession.getMapper(userMapper.class);
		User user1 = mapper.finduserbyusername("3");
		System.out.println(user1);
		//mapper.updateuser(new User("3", "3", ""));
		User user2 = mapper.finduserbyusername("3");
		sqlSession.close();
		System.out.println(user2);
	}
結果

20:46:35,738 DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger debug:139 -> ==>  Preparing: select username,password,permission from user where username=?; 
20:46:35,787 DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger debug:139 -> ==> Parameters: 3(String)
20:46:35,808 DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger debug:139 -> <==      Total: 1
User [username=3, password=3, permission=]
20:46:35,809 DEBUG org.apache.ibatis.cache.decorators.LoggingCache getObject:62 -> Cache Hit Ratio [com.my.shiro.Dao.userMapper]: 0.0
20:46:35,813 DEBUG org.springframework.jdbc.datasource.DataSourceUtils doReleaseConnection:327 -> Returning JDBC Connection to DataSource
User [username=3, password=3, permission=]
這裏也只執行一次sql,但是注意看多了一條cache hit ratio這裏有一個命中率,也就表示二級緩存開啓。

這裏如果你想要某條語句不開啓二級緩存,就比如果密碼查詢等等,這樣不適合開啓二級緩存配置。

<select id="finduserbyusername" resultMap="BaseResultMap" parameterType="java.lang.String" useCache="false">
		select <include refid="Base_Column_List"/>
	    from user
	    where username=#{username};
	</select>

這裏也就是添加一個屬性userCache設置false就是關閉這個sql語句二級緩存,設置代碼就不貼上去,結果也差不多就是之前沒有開啓二級緩存的。

mybatis自身緩存的弊

由於mybatis不是一個專門做緩存處理,現在有一個十分明顯的弊端就是,一般我們的網頁就是分佈式的發佈,也就是最少使用兩個服務器,如果使用兩個服務器mybatis的緩存技術就無法在兩個服務器通用就是,也就是兩個服務器無法達到數據通用,比如我在一個服務器存儲了我的信息,但是我轉跳到另一個服務器那使用mybatis數據就是需要從新加載,這裏就是一個非常大的問題。還有就是mybatis無法實現細粒度的緩存管理,當你查詢大量數據的時候而且將數據存儲到mybatis二級緩存中的時候,但是一旦隊一個數據操作增加,刪除,修改,這裏二級緩存就全部清空,而mybatis無法實現對這裏單個信息的修改,這裏可以使用三級緩存,三級緩存需要自己實現。

mybatis與緩存框架整合

緩存框架這裏使用ehcache作爲例子,ehcache就是一個分佈式框架。

mapper文件配置

<!-- 開啓本mapper(namespace)的二級緩存 
  		type:指定cache接口的實現類型,mybatis默認的是PerpetualCache
  		如果要和ehcache整合只需要配置type爲ehacache的實現類即可
  		-->
  	<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
  	

這裏只需要配置cache的type就可以,這樣就可以將緩存數據交給ehcache管理。

ehcache配置文件

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
  updateCheck="false">
	<!--diskStore:緩存數據持久化的目錄 地址  -->
	<diskStore path="c:\temp\lhd"/>
	<defaultCache 
		maxElementsInMemory="1000" 
		maxElementsOnDisk="10000000" 
		eternal="false" 
		overflowToDisk="false" 
		diskPersistent="false" 
		timeToIdleSeconds="120" 
		timeToLiveSeconds="120" 
		diskExpiryThreadIntervalSeconds="120" 
		memoryStoreEvictionPolicy="LRU">
	</defaultCache>
</ehcache>
這裏就是一些緩存策略。




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