Mybatis一級緩存,二級緩存源碼解析與調優。以及網上某些錯誤糾正

在網上看了很多關於Mybatis的源碼解析,最後自己看了下源碼,發現和某些博主說的並不一樣。

1.關於全局緩存的配置
如果在mybatis.xml配置中配置了

設置全局緩存
並不會使用二級緩存。在某些博客裏我看到某些博主說這個選項是默認關閉的。但是看了源碼會發現這個選項默認是開啓的。

Mybatis配置類中的默認值爲true
Configuration類是mybatis配置對應的一個類,所有配置相關信息都會被封裝到這個類的對象中以便給後續使用。
解析XML時設置Configuration的cacheEnabled屬性
XML解析類在解析cacheEnabled節點時,會把解析完的值通過configuration的setCacheEnabled方法設置到Configuration的對象中去。而且默認值是true!

所以mybatis配置中的cacheEnabled屬性默認是開的!

cacheEnabled這個屬性只是設置是否在我們的Executor外面包裹一層CachingExecutor的代理。如果包裹了就代表採用了二級緩存的第一步,但還需要第二步才能真正的使用二級緩存。

cacheEnabled設置成false時的Executor
當我們手動把cacheEnabled設置成false的時候。false
上面SqlSession裏組合的Executor只是一個簡單的SimpleExecutor,並沒有裹上任何代理。

接下來把cacheEnabled設置成true。true

caching
可以發現SimpleExecutor外面裹了一層CachingExcutor的代理。
從代碼上更直觀一點看

是創建Executor時根據是否cacheEnabled裹上的。

這時候是不是二級緩存就使用成功了呢?

接下來我使用Jmeter進行服務器壓測。

100

我開啓了100個用戶線程無休止地對服務器發送查詢請求。

一段時間後拋出異常。
異常
這個異常表示大量請求需要獲得數據庫連接,但是數據庫池的連接數有限。最終線程在等待不到數據庫連接的情況下,拋出上述超時異常。

之所以得不到數據庫連接是因爲沒有使用緩存,高併發的情況下每個用戶都要求獲得數據庫連接來訪問數據庫,數據庫連接數有限,沒辦法每個人都得到一條連接,導致某些用戶等待數據庫連接過久拋出超時異常。

上述所說的沒有使用的緩存,包含了一級緩存(localCache) 和二級緩存。本例使用的Mapper是用@AutoWire自動注入的,自動注入的Mapper在每次CRUD方法執行完之後都會關閉一次SqlSession,所以一級緩存不能使用。具體請見通過手動打開的Mapper和自動注入的Mapper的關閉連接處理區別

真正開啓二級緩存在全局設置cacheEnabled是不夠的,它只會允許使用CachingExecutor。

看到CachingExcutor的query方法。這時候的MappedStatement裏的緩存cache是null。二級緩存是每一個MappedStatement對應一個cache,(每條語句對應一個查詢結果的緩存cache)。CachingExecutor中TransactionalCacheManager的TransactionalCache代理了每個MappedStatement的Cache。拿是從cache中直接拿緩存,但是放和刪除緩存的時候會先在TransactionalCache自己的兩個容器中操作。
在這裏插入圖片描述
在提交時才一併把這兩個容器裏的緩存提交到真正的,被代理的cache緩存裏。
事務cache代理cache

在這裏插入圖片描述

接下來我爲我們壓測的請求用到的Mapper文件加上了cache節點。這時候二級緩存才真正開啓。

cache
剛剛說過,每個MappedStatement對應一個cache(二級)。
在沒有加<cache/>節點的時候這個cache是null的,如果加了才能讓這個cache不爲null。

代碼證明:

在這裏插入圖片描述

在這裏插入圖片描述

在這裏插入圖片描述最終找到了如下的源頭代碼,只有用<cache/>纔會使用到useNewCache方法使得MappedStatement的cache不爲空!

在這裏插入圖片描述

現在讓我們重啓服務器,開啓Jmeter繼續壓測。

這時候再看CachingExecutor的query方法。
在這裏插入圖片描述
cache終於不爲空了!並且mybatis默認給我們的cache套了一層基於LRU(Least Recently Used,到達上限時,最近用得最少的將會被首先移除)的cache,並且這個cache的上限是1024在這裏插入圖片描述在壓測一段時間後,LruCache的大小維持在了1024。
在這裏插入圖片描述
並且也不會報數據庫連接超時的錯誤了,因爲查詢時先從緩存中查詢,而不是直接請求數據庫連接來訪問數據庫。

總結。
1:在全局中設置<cacheEnabled>爲true並不能有效的開啓二級緩存,必須在Mapper的XML節點中也進行相關設置。
2.<cacheEnabled>默認是true的!

結尾:其實二級緩存也不能濫用,雖然有Lru的限制,但是如果每個被緩存的對象都很大,服務器的內存又少的話,容易產生OOM。還是需要按照服務器的情況設置二級緩存是否使用以及緩存的大小。

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