緩存在互聯網系統中是很是重要的, 其主要做用是將數據保存到內存中, 當用戶查詢數據 時, 優先從緩存容器中獲取數據,而不是頻繁地從數據庫中查詢數據,從而提升查詢性能。目 前流行的緩存服務器有MongoDB 、Redis 、Ehcache 等,不一樣的緩存服務器有不一樣的應用場景, 不存在孰優孰劣。 MyBatis 提供一級緩存和二級緩存的機制。一級緩存是SqlSession 級別的緩存, 在操做數據 庫時, 每一個SqlSession 類的實體對象中都有一個HashMap 數據結構能夠用來緩存數據,不一樣的 SqlSession 類的實例對象緩存的HashMap 數據結構互不影響。二級緩存是Mapper 級別的緩存, 數據庫
My Batis 的緩存模式如圖所示:緩存
MyBatis 的一級緩存是SqI Session 級別的緩存, 在操做數據庫時須要構造Sq!Session 對象。 每一個SqISession 對象中都有一個HashMap 對象用於緩存數據,不一樣的SqlSession 之間的緩存數 據區域互不影響。 MyBatis的一級緩存做用域是SqlSession 範圍的,在參數和SQL 徹底同樣的狀況下,使用 同一個SqlSession 對象調用同一個Mapper 方法,每每只執行一次SQL ,由於MyBatis 會將數據 放在緩存中,下次查詢的時候,若是沒有聲明須要刷新緩存而且緩存沒有超時, SqlSession 都 只會取出當前緩存的數據,而不會再次發送SQL 到數據庫中。須要注意的是,若是SqlSession 執行了DML 操做( insert 、update 和delete ),並提交到數據庫, MyBatis 會清空SqlSession 中 的一級緩存,這樣作的目的是爲了保證緩存中存儲的是最新的信息, 以免出現髒讀現象。 MyBatis 的緩存機制是基於id 進行緩存的, MyBatis 使用HashMap 緩存數據時,使用對象的id 做爲key,而對象則做爲value 保存。服務器
上述代碼中,經過@Resource 註解注入SqlSessionFactoryBean 對象, SqlSessionFactoryBean 對象在applicationContext.xml 配置文件中己配置, 具體代碼以下:session
經過SqlSessionFactory 工廠獲取SqlSession 對象, 經過SqlSession 對象的getMapper()方法 獲取AyUserDao 接口對象, 並執行AyUserDao 接口對象的findByld()方法。AyUserDao 和 AyUserMapper.xml 的代碼以下所示。數據結構
執行測試用例testsessionCach e(),控制檯打印相關的信息,具體如圖9-2 所示。mybatis
由圖9 -2 中控制檯打印的信息能夠看出,第一次查詢和第二次查詢,查詢SQL 的日誌只輸 出一遍, 這就說明了第二次查詢的數據不是從數據庫查詢出來的,是從一級緩存中獲取的。app
MyBatis 在開啓一個Session 會話時, 會建立一個新的SqISession 對象, 每一個SqlSession 對 象會建立一個新的Executor 對象, Executor 對象中持有一個新的PerpetualCache 對象: 當會話結 束時, SqISession 對象及其內部的Executor 對象還有PerpetualCache 對象也會一併釋放掉,即: (1 )若是SqlSession 調用了close()方法,會釋放掉一級緩存PerpetualCache 對象, 一級緩 存不可用。 (2 )若是SqlSession 調用了clearCache(), 會清空PerpetualCache 對象中的數據,可是該對 象仍可以使用。 ( 3 ) SqlSession 中執行任何一個DDL 操做( update 、delete 、insert) ,都會清空 PerpetualCache 對象的數據,可是該對象能夠繼續使用。性能
二級緩存是Mapper 級別的緩存。使用二級緩存時,多個SqlSession 使用同一個Mapper ( namespace )的SQL 語句操做數據庫,獲得的數據會存在二級緩存區域,二級緩存一樣是使用 HashMap 進行數據存儲。二級緩存比一級緩存做用域範圍更大,多個SqISession 能夠共用二級 緩存,二級緩存是跨SqISession 的。當某個SqISession 類的實例對象執行了增、刪、改等操做 時, Mapper 實例會清空二級緩存。MyBatis 默認沒有開啓二級緩存,須要在配置中開啓二級緩 存。開啓二級緩存的步驟以下。測試
首先,在applicationContext.xml 配置文件中添加以下配置:spa
上面配置信息中最重要的就是指定MyBatis 配置文件的位置:
其次,在src\main\resources 目錄下添加配置文件mybatis-config . xml , 具體代碼以下:
最後,因爲二級緩存是Mapper 級別的,還要在須要開啓二級緩存的具體mapper.xml 文件 中開啓二級緩存,方法很簡單,只須要在mappe川ml 文件中添加一個cache 標籤既可,具體代 碼以下所示:
cache 標籤有不少屬性,經常使用的屬性如表9- 1 所示:
AyUserDao 和AyUserMapper.xml 代碼以下:
當開啓MyBatis 二級緩存後,執行測試用例testSessionCache(), 控制檯打印相關的信息, 具體如圖9-4 所示。
由圖9-4 可知, 第一次查詢數據時, 獲取鏈接、編譯SQL、加載了數據庫中的數據。而第 二次查詢數據以前,進行了update 操做,至關於進行commit 操做,也就是說會清空一級緩存來 保證數據的最新狀態。可是開啓了二級緩存,在第二次查詢時,會從二級緩存中獲取數據。 這裏須要注意的是,若是在select 標籤中設置「 userCache = false」 能夠禁用當前select 語句 的二級緩存,具體代碼以下:
這裏簡單總結一下二級緩存的特色:
還須要注意的是,使用二級緩存須要特別謹慎,有時候不一樣的namespace 下的SQL 配置可 能緩存了相同的數據。例如AyUserMapper.xml 中有不少查詢緩存了用戶數據,其餘的 XXXMapper且nl 中有針對用戶表進行單表操做, 也緩存了用戶數據,若是在AyUserMapper.xml 中作了刷新緩存的操做,在XXXMapper.xml 中的緩存數據仍然有效, 這樣在查詢數據時可能會 出現髒數據。因此使用MyBatis 的二級緩存時,要根據具體的業務狀況,謹慎使用。
###cache-ref共享緩存
MyBatis 並非整個Application 只有一個Cache 緩存對象,它將緩存劃分的更細, 也就是 Mapper 級別的,即每個Mapper 均可以擁有一個Cache 對象,具體以下:
( 1 ) 爲每個Mapper 分配一個Cache 緩存對象(使用<cache>節點配置) 。 ( 2 )多個Mapper 共用一個Cache 緩存對象(使用<cache-ref>節點配置) 。
若是想讓多個Mapper 共用一個Cache ,可使用<cache-ref namespace="與節點,來指定這 個Mapper 共享哪個Mapper 的Cache 緩存。具體如圖9-5 所示。
如圖9- 6 所示, 一個SqlSession 對象中建立一個本地緩存( local cache ),對於每次查詢, 都會根據查詢條件去一級緩存中查找,若是緩存中存在數據,就直接從緩存中取出,而後返回 給用戶:不然,從數據庫讀取數據,將查詢結果存入緩存並返回給用戶。
SqlSession 將它的工做交給了Executor 執行器這個角色來完成,負責完成對數據庫的各類 操做。當建立一個SqlSession 對象時, MyBatis 會爲這個SqlSession 對象建立一個新的Executor 執行器,而緩存信息就被維護在這個Executor 執行器中, MyBatis 將緩存和對緩存相關的操做 封裝成了Cache 接口。
如圖9 - 7 所示, MyBatis 的二級緩存機制的關鍵是使用Executor 對象。當開啓SqlSession 會 話時, 一個Session 對象使用一個Executor 對象來完成會話操做。若是用戶配置了 "cacheEnabled=true」, 那麼MyBatis 在爲SqlSession 對象建立Executor 對象時,會對Executor 對 象加上一個裝飾者: CachingExecutor ,這時SqISession 使用CachingExecutor 對象來完成操做請 求。CachingExecutor 對於查詢請求,會先判斷該查詢請求在二級緩存中是否有緩存結果,若是 有查詢結果, 則直接返回緩存結果:若是緩存中沒有, 再交給真正的Executor 對象來完成查詢 操做,以後CachingExecutor 會將真正Executor 返回的查詢結果放置到緩存中,而後再返回給 用戶。