理解mybatis中緩存
一級緩存(本地緩存):sqlSession級別的緩存,一級緩存一直都是開啓的,sqlSession級別的Map,與數據庫同一次回話期間查詢到的數據都會放在本地緩存當中,以後如果要查詢相同的數據,直接從緩存當中獲取,而不要向數據庫發送請求獲得數據了。
//一級緩存的體驗
@Test
public void test05() throws IOException {
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
SqlSession sqlSession = sqlSessionFactory.openSession(true);
try {
EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
//根據id查詢數據
Employee employee = employeeMapper.getEmployeeById(1);
System.out.println(employee);
//再次查詢
Employee employee2 = employeeMapper.getEmployeeById(1);
System.out.println(employee2);
} finally {
sqlSession.close();
}
}
查詢的結果:只會向數據庫發送一次請求。
DEBUG 04-15 22:17:55,203 ==> Preparing: SELECT `id`, `lastname`, `email`, `birth`, `createtime`, `emp_image`, `department_id` FROM `employee` WHERE id=? (BaseJdbcLogger.java:145)
DEBUG 04-15 22:17:55,292 ==> Parameters: 1(Integer) (BaseJdbcLogger.java:145)
DEBUG 04-15 22:17:55,328 <== Total: 1 (BaseJdbcLogger.java:145)
Employee [id=1, lastname=劉東平, [email protected], birth=Wed Mar 27 19:50:12 CST 2019, createtime=Wed Mar 27 19:50:16 CST 2019, emp_image=, department=null]
Employee [id=1, lastname=劉東平, [email protected], birth=Wed Mar 27 19:50:12 CST 2019, createtime=Wed Mar 27 19:50:16 CST 2019, emp_image=, department=null]
思考:那些情況,一級緩存會失效?
1.sqlSession對象不是同一個對象了,就是說出現了兩次會話了。
2.如果sqlSession相同,但是查詢的條件不同,很顯然還是會發送請求,因爲你的緩存中沒有數據,所以查詢條件不同,還會進行。
3.如果sqlSession相同,但是在期間進行了增刪改,那麼也會發送sql語句,因爲進行數據庫操作必然會發送變化。
4.如果sqlSession相同,但是我們手動清除了緩存(sqlSession.clearCache()。
*二級緩存(全局緩存):*二級緩存是基於namespace級別的緩存機制,也就是說一個namespace就對應着一個的二級緩存。
二級緩存的工作機制:
1.一個會話,查詢一條數據。這個數據就會放在當前會話的一級緩存當中,
2.如果該會話關閉了,一級緩存中保存的數據會保存到二級緩存中,新的回話查詢信息,就可以參照二級緩存中的數據進行,選擇性的知道自己是否該發送sql語句了
3.sqlSession===EmployeeMapper=>Employee
sqlSession=>DepartmentMapper=>department
不同的namespace查出的數據會保存在自己的緩存當中(Map)
二級緩存(second level cache),全局作用域緩存
• 二級緩存默認不開啓,需要手動配置
• MyBatis提供二級緩存的接口以及實現,緩存實現要求
POJO實現Serializable接口
• 二級緩存在 SqlSession 關閉或提交 之後纔會 生效
怎麼使用二級緩存:
1.需要在mybatis-config.xml配置文件中配置:
<settings>.
<setting name="cacheEnabled" value="true"/>
</setteings>
2.需要在xxxxMapper.xml文件內配置
<cache></cache>
3.每個pojo都必須實現序列化接口
• 使用步驟
– 1、全局配置文件中開啓二級緩存
• <setting name= "cacheEnabled" value="true"/>
– 2、需要使用二級緩存的映射文件處使用cache配置緩存
• <cache />
– 3、注意:POJO需要實現Serializable接
緩存相關屬性
• eviction=“ FIFO” :緩存回收策略:
LRU – 最近最少使用的:移除最長時間不被使用的對象。
FIFO – 先進先出:按對象進入緩存的順序來移除它們。
SOFT – 軟引用:移除基於垃圾回收器狀態和軟引用規則的對象。
WEAK – 弱引用:更積極地移除基於垃圾收集器狀態和弱引用規則的對象。
默認的是 LRU
。*
• flushInterval :刷新間隔,單位毫秒
默認情況是不設置,也就是沒有刷新間隔,緩存僅僅調用語句時刷新
• size :引用數目,正整數 代表緩存最多可以存儲多少個對象,太大容易導致內存溢出
• readOnly :只讀,true/false
true:只讀緩存;會給所有調用者返回緩存對象的相同實例。因此這些對象
不能被修改。這提供了很重要的性能優勢。
false:讀寫緩存;會返回緩存對象的拷貝(通過序列化)。這會慢一些,
但是安全,因此默認是 false。
1、全局setting的cacheEnable:
– 配置二級緩存的開關。一級緩存一直是打開的。
• 2、select標籤的useCache屬性:
– 配置這個select是否使用二級緩存。一級緩存一直是使用的
• 3、sql標籤的flushCache屬性:
– 增刪改默認flushCache=true。sql執行以後,會同時清空一級和二級緩存。
查詢默認flushCache=false。
• 4、sqlSession.clearCache():
– 只是用來清除一級緩存。
• 5、當在某一個作用域
(一級緩存Session/二級緩存 Namespaces) 進行了
C/U/D 操作後,默認該作用域下 所有 select 中的緩存將被 clear
配置之後體驗二級緩存
//二級緩存的體驗
@Test
public void test06() throws IOException {
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
SqlSession sqlSession = sqlSessionFactory.openSession(true);
SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
try {
EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
EmployeeMapper employeeMapper2 = sqlSession2.getMapper(EmployeeMapper.class);
//根據id查詢數據
Employee employee = employeeMapper.getEmployeeById(1);
System.out.println(employee);
sqlSession.close();
//再次查詢
Employee employee2 = employeeMapper2.getEmployeeById(1);
System.out.println(employee2);
} finally {
sqlSession2.close();
}
}
查詢的打印結果:只會打印一條SQL語句
DEBUG 04-15 23:09:50,016 Cache Hit Ratio [com.ldp.mybatis.dao.EmployeeMapper]: 0.0 (LoggingCache.java:62)
DEBUG 04-15 23:09:50,026 ==> Preparing: SELECT `id`, `lastname`, `email`, `birth`, `createtime`, `emp_image`, `department_id` FROM `employee` WHERE id=? (BaseJdbcLogger.java:145)
DEBUG 04-15 23:09:50,092 ==> Parameters: 1(Integer) (BaseJdbcLogger.java:145)
DEBUG 04-15 23:09:50,127 <== Total: 1 (BaseJdbcLogger.java:145)
Employee [id=1, lastname=劉東平, [email protected], birth=Wed Mar 27 19:50:12 CST 2019, createtime=Wed Mar 27 19:50:16 CST 2019, emp_image=, department=null]
DEBUG 04-15 23:09:50,257 Cache Hit Ratio [com.ldp.mybatis.dao.EmployeeMapper]: 0.5 (LoggingCache.java:62)
Employee [id=1, lastname=劉東平, [email protected], birth=Wed Mar 27 19:50:12 CST 2019, createtime=Wed Mar 27 19:50:16 CST 2019, emp_image=, department=null]
細節:第一次查詢的會話完畢或者關閉後,一級緩存中的數據纔會轉移到二級緩存當中。
緩存相關的設置:
1.cacheEnabled=true|false 關閉的是二級緩存,一級緩存一直都會存在。
2.每個select標籤都會有useCache=true|false:不使用二級緩存。不影響一級緩存
3.每個增刪改上面也會有flushCache=true||false
增刪改執行完之後,清除緩存
測試:爲true 一級緩存會被清除,二級必然也會清除。
查詢標籤也會有相應的情況出現:
4.sqlSession.clearCache:只是清除當前sqlSession的一級緩存
5.localCacheScope(本地緩存):(一級緩存session)存放數據
**
一級緩存和二級緩存的總結:
**
第三方(ehcache)的二級緩存實現:
1.導入第三方的緩存包ehcache-core-2.6.8.jar
2.導入整合包mybatis-ehcache-1.0.3.jar 兩個日誌包slf4j-api-1.6.1.jar… slf4j-log4j12-1.6.2.jar
3.加入ehcache.xml文件
4.在需要添加二級緩存的配置文件添加
<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache> |
---|
其中ehcache.xml文件內容
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<!-- 磁盤保存路徑 -->
<diskStore path="D:\44\ehcache" />
<defaultCache
maxElementsInMemory="10000"
maxElementsOnDisk="10000000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
</ehcache>
<!--
屬性說明:
l diskStore:指定數據在磁盤中的存儲位置。
l defaultCache:當藉助CacheManager.add("demoCache")創建Cache時,EhCache便會採用<defalutCache/>指定的的管理策略
以下屬性是必須的:
l maxElementsInMemory - 在內存中緩存的element的最大數目
l maxElementsOnDisk - 在磁盤上緩存的element的最大數目,若是0表示無窮大
l eternal - 設定緩存的elements是否永遠不過期。如果爲true,則緩存的數據始終有效,如果爲false那麼還要根據timeToIdleSeconds,timeToLiveSeconds判斷
l overflowToDisk - 設定當內存緩存溢出的時候是否將過期的element緩存到磁盤上
以下屬性是可選的:
l timeToIdleSeconds - 當緩存在EhCache中的數據前後兩次訪問的時間超過timeToIdleSeconds的屬性取值時,這些數據便會刪除,默認值是0,也就是可閒置時間無窮大
l timeToLiveSeconds - 緩存element的有效生命期,默認是0.,也就是element存活時間無窮大
diskSpoolBufferSizeMB 這個參數設置DiskStore(磁盤緩存)的緩存區大小.默認是30MB.每個Cache都應該有自己的一個緩衝區.
l diskPersistent - 在VM重啓的時候是否啓用磁盤保存EhCache中的數據,默認是false。
l diskExpiryThreadIntervalSeconds - 磁盤緩存的清理線程運行間隔,默認是120秒。每個120s,相應的線程會進行一次EhCache中數據的清理工作
l memoryStoreEvictionPolicy - 當內存緩存達到最大,有新的element加入的時候, 移除緩存中element的策略。默認是LRU(最近最少使用),可選的有LFU(最不常使用)和FIFO(先進先出)
-->