mybatis查询缓存——(十三)
1.???? mybatis緩存介紹
如下圖,是mybatis一級緩存和二級緩存的區別圖解:
mybatis提供查詢緩存,用于減輕數據壓力,提高數據庫性能。
mybaits提供一級緩存,和二級緩存。
一級緩存是SqlSession級別的緩存。在操作數據庫時需要構造 sqlSession對象,在對象中有一個數據結構(HashMap)用于存儲緩存數據。不同的sqlSession之間的緩存數據區域(HashMap)是互相不影響的。
?
二級緩存是mapper級別的緩存,多個SqlSession去操作同一個Mapper的sql語句,多個SqlSession可以共用二級緩存,二級緩存是跨SqlSession的。
?
為什么要用緩存?
如果緩存中有數據就不用從數據庫中獲取,大大提高系統性能。
?
2. ??? 一級緩存
2.1 ??? 一級緩存工作原理
緩存原理: 對sql語句進行計算后得出一個key值,根據此key查詢緩存中是否有與此key相同的數據,如果沒有查到就從數據庫查詢(會發出SQL語句查詢)并將結果一級寫入緩存。如果根據key值查到就直接返回結果。緩存就是一個hashmap。LocalCache是一級緩存的區域(HashMap).
?
第一次發起查詢用戶id為1的用戶信息,先去找緩存中是否有id為1的用戶信息,如果沒有,從數據庫查詢用戶信息。得到用戶信息,將用戶信息存儲到一級緩存中。
?
如果sqlSession去執行commit操作(執行插入、更新、刪除),清空SqlSession中的一級緩存,這樣做的目的為了讓緩存中存儲的是最新的信息,避免臟讀。
?
第二次發起查詢用戶id為1的用戶信息,先去找緩存中是否有id為1的用戶信息,緩存中有,直接從緩存中獲取用戶信息。
?
2.2 ?? 一級緩存測試(根據日志信息是否發出SQL語句查詢即可判斷是否進行讀數據庫)
mybatis默認支持一級緩存,不需要在配置文件去配置。
按照上邊一級緩存原理步驟去測試。
@Testpublic void testCache1() throws Exception{SqlSession sqlSession = sqlSessionFactory.openSession();//創建代理對象 UserMapper userMapper = sqlSession.getMapper(UserMapper.class);//下邊查詢使用一個SqlSession//第一次發起請求,查詢id為1的用戶 User user1 = userMapper.findUserById(1);System.out.println(user1);// 如果sqlSession去執行commit操作(執行插入、更新、刪除),清空SqlSession中的一級緩存,這樣做的目的為了讓緩存中存儲的是最新的信息,避免臟讀。//更新user1的信息 user1.setUsername("測試用戶22");userMapper.updateUser(user1);//執行commit操作去清空緩存 sqlSession.commit();//第二次發起請求,查詢id為1的用戶 User user2 = userMapper.findUserById(1);System.out.println(user2);sqlSession.close();}?
2.3 ?? 一級緩存應用
正式開發,是將mybatis和spring進行整合開發,事務控制在service中。
一個service方法中包括 很多mapper方法調用。
?
service{
???????? //開始執行時,開啟事務,創建SqlSession對象
???????? //第一次調用mapper的方法findUserById(1)
????????
???????? //第二次調用mapper的方法findUserById(1),從一級緩存中取數據
???????? //方法結束,sqlSession關閉
}
?
如果是執行兩次service調用查詢相同 的用戶信息,不走一級緩存,因為service方法結束,sqlSession就關閉,一級緩存就清空。
?
3. ??? 二級緩存
3.1 原理
原理:
首先從緩存中查找,沒找到就進行數據庫查詢,查詢出的結果寫入二級緩存,并計算命中率,第一次沒找到命中率為0;第二次通過先從緩存中查找,找到之后命中率為0.5.
?
首先開啟mybatis的二級緩存。
sqlSession1去查詢用戶id為1的用戶信息,查詢到用戶信息會將查詢數據存儲到二級緩存中。
如果SqlSession3去執行相同 mapper下sql,執行commit提交,清空該 mapper下的二級緩存區域的數據。
sqlSession2去查詢用戶id為1的用戶信息,去緩存中找是否存在數據,如果存在直接從緩存中取出數據。
?
二級緩存與一級緩存區別,二級緩存的范圍更大,多個sqlSession可以共享一個UserMapper的二級緩存區域。
UserMapper有一個二級緩存區域(按namespace分) ,其它mapper也有自己的二級緩存區域(按namespace分)。
每一個namespace的mapper都有一個二緩存區域,兩個mapper的namespace如果相同,這兩個mapper執行sql查詢到數據將存在相同 的二級緩存區域中。
?
3.2 ??? 開啟二級緩存
mybaits的二級緩存是mapper范圍級別,除了在SqlMapConfig.xml設置二級緩存的總開關,還要在具體的mapper.xml中開啟二級緩存。
1. 在核心配置文件SqlMapConfig.xml中加入
<setting name="cacheEnabled" value="true"/>
?
| ? | 描述 | 允許值 | 默認值 |
| cacheEnabled | 對在此配置文件下的所有cache 進行全局性開/關設置。 | true false | true |
?
?
?
2.?UserMapper.xml中開啟二緩存
在UserMapper.xml中開啟二緩存,UserMapper.xml下的sql執行完成會存儲到它的緩存區域(HashMap)。
3. ??? 調用pojo類實現序列化接口
為了將緩存數據取出執行反序列化操作,因為二級緩存數據存儲介質多種多樣,不一定在內存。
4. ??? 測試方法(根據日志信息是否發出SQL語句查詢即可判斷是否進行讀數據庫)
// 二級緩存測試 @Testpublic 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();}?
5. ??? useCache配置
在statement中設置useCache=false可以禁用當前select語句的二級緩存,即每次查詢都會發出sql去查詢,默認情況是true,即該sql使用二級緩存。
<select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">
總結:針對每次查詢都需要最新的數據sql,要設置成useCache=false,禁用二級緩存。
7. ??? 刷新緩存(就是清空緩存)
在mapper的同一個namespace中,如果有其它insert、update、delete操作數據后需要刷新緩存,如果不執行刷新緩存會出現臟讀。
?
?設置statement配置中的flushCache="true"?屬性,默認情況下為true即刷新緩存,如果改成false則不會刷新。使用緩存時如果手動修改數據庫表中的查詢數據會出現臟讀。
如下:
<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User" flushCache="true">
?
總結:一般下執行完commit操作都需要刷新緩存,flushCache=true表示刷新緩存,這樣可以避免數據庫臟讀。
?
4. ??? mybatis整合ehcache(重點)
ehcache是一個分布式緩存框架。
4.1???? 分布緩存
我們系統為了提高系統并發,性能、一般對系統進行分布式部署(集群部署方式)
?
不使用分布緩存,緩存的數據在各各服務單獨存儲,不方便系統 開發。所以要使用分布式緩存對緩存數據進行集中管理。
mybatis無法實現分布式緩存,需要和其它分布式緩存框架進行整合。
4.2 ??? 整合方法(掌握)
mybatis提供了一個cache接口,如果要實現自己的緩存邏輯,實現cache接口開發即可。
mybatis和ehcache整合,mybatis和ehcache整合包中提供了一個cache接口的實現類。
?
mybatis默認實現cache類是:
?
4.3 ?? 加入ehcache包
?
4.4 ??? 整合ehcache
配置mapper中cache中的type為ehcache對cache接口的實現類型。
4.5 ?? 加入ehcache的配置文件
ehcache.xml
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:noNamespaceSchemaLocation="../config/ehcache.xsd"><diskStore path="F:\develop\ehcache" /><defaultCache maxElementsInMemory="1000" maxElementsOnDisk="10000000"eternal="false" overflowToDisk="false" timeToIdleSeconds="120"timeToLiveSeconds="120" diskExpiryThreadIntervalSeconds="120"memoryStoreEvictionPolicy="LRU"></defaultCache> </ehcache>?
5. ??? 二級應用場景
?
對于訪問多的查詢請求且用戶對查詢結果實時性要求不高,此時可采用mybatis二級緩存技術降低數據庫訪問量,提高訪問速度,業務場景比如:耗時較高的統計分析sql、電話賬單查詢sql等。
???????? 實現方法如下:通過設置刷新間隔時間,由mybatis每隔一段時間自動清空緩存,根據數據變化頻率設置緩存刷新間隔flushInterval,比如設置為30分鐘、60分鐘、24小時等,根據需求而定。
?
?
6???? 二級緩存局限性
?
???????? mybatis二級緩存對細粒度的數據級別的緩存實現不好,比如如下需求:對商品信息進行緩存,由于商品信息查詢訪問量大,但是要求用戶每次都能查詢最新的商品信息,此時如果使用mybatis的二級緩存就無法實現當一個商品變化時只刷新該商品的緩存信息而不刷新其它商品的信息,因為mybaits的二級緩存區域以mapper為單位劃分,當一個商品信息變化會將所有商品信息的緩存數據全部清空。解決此類問題需要在業務層根據需求對數據有針對性緩存。
?
轉載于:https://www.cnblogs.com/qlqwjy/p/7296070.html
總結
以上是生活随笔為你收集整理的mybatis查询缓存——(十三)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android - Animation(
- 下一篇: WebDriver自动化测试工具(3)-