mybatis有一級和二級緩存,一級是sqlSession級別,二級是application級別。
一級緩存的生命周期:
a. MyBatis在開啟一個數據庫會話時,會創建一個新的SqlSession對象,SqlSession對象中會有一個新的Executor(接口),Executor對象中持有一個新的PerpetualCache對象;當會話結束時,SqlSession對象及其內部的Executor對象還有PerpetualCache對象也一并釋放掉。
b. 如果SqlSession調用了close()方法,會釋放掉一級緩存PerpetualCache對象,一級緩存將不可用;
c. 如果SqlSession調用了clearCache(),會清空PerpetualCache對象中的數據,但是該對象仍可使用;
d.SqlSession中執行了任何一個update操作(update()、delete()、insert()) ,都會清空PerpetualCache對象的數據,但是該對象可以繼續使用;
一級緩存的工作流程:
一級緩存用的是HashMap,根據Key查詢數據,沒有就去數據庫查詢然后放在緩存中。
如何構建這個Key是關鍵,Cache接口的設計以及CacheKey的定義(非常重要)
將本次查詢使用的特征值作為key,將查詢結果作為value存儲到Map中。
現在最核心的問題出現了:怎樣來確定一次查詢的特征值?
換句話說就是:怎樣判斷某兩次查詢是完全相同的查詢?
也可以這樣說:如何確定Cache中的key值?
mybatis底層是jdbc,通過4個條件確定這個KEY。
- 傳入的 statementId
- 查詢時要求的結果集中的結果范圍 (結果的范圍通過rowBounds.offset和rowBounds.limit表示);
- 這次查詢所產生的最終要傳遞給JDBC java.sql.Preparedstatement的Sql語句字符串(boundSql.getSql() )
- 傳遞給java.sql.Statement要設置的參數值
一級緩存的性能分析
1.MyBatis對會話(Session)級別的一級緩存設計的比較簡單,就簡單地使用了HashMap來維護,并沒有對HashMap的容量和大小進行限制。
讀者有可能就覺得不妥了:如果我一直使用某一個SqlSession對象查詢數據,這樣會不會導致HashMap太大,而導致 java.lang.OutOfMemoryError錯誤啊? 讀者這么考慮也不無道理,不過MyBatis的確是這樣設計的。
MyBatis這樣設計也有它自己的理由:
a. 一般而言SqlSession的生存時間很短。一般情況下使用一個SqlSession對象執行的操作不會太多,執行完就會消亡;
b. 對于某一個SqlSession對象而言,只要執行update操作(update、insert、delete),都會將這個SqlSession對象中對應的一級緩存清空掉,所以一般情況下不會出現緩存過大,影響JVM內存空間的問題;
c. 可以手動地釋放掉SqlSession對象中的緩存。
- 一級緩存是一個粗粒度的緩存,沒有更新緩存和緩存過期的概念
MyBatis的一級緩存就是使用了簡單的HashMap,MyBatis只負責將查詢數據庫的結果存儲到緩存中去, 不會去判斷緩存存放的時間是否過長、是否過期,因此也就沒有對緩存的結果進行更新這一說了。
根據一級緩存的特性,在使用的過程中,我認為應該注意:
1、對于數據變化頻率很大,并且需要高時效準確性的數據要求,我們使用SqlSession查詢的時候,要控制好SqlSession的生存時間,SqlSession的生存時間越長,它其中緩存的數據有可能就越舊,從而造成和真實數據庫的誤差;同時對于這種情況,用戶也可以手動地適時清空SqlSession中的緩存;
2、對于只執行、并且頻繁執行大范圍的select操作的SqlSession對象,SqlSession對象的生存時間不應過長。