![使用Mybatis導致的OutOfMemoryError錯誤](http://p2.ttnews.xyz/loading.gif)
使用Mybatis導致的OutOfMemoryError錯誤
我們系統中是用Mybatis開發,這個系統在生產環境運行了好幾個月的時間了,沒有出現過很嚴重的問題,突然有一天集群中的有2臺報警無法提供服務,運維重啟服務後正常。因為是生產上的問題,我們需要定位根本原因,查了那兩臺機器的日誌,發現有OutOfMemoryError錯誤,錯誤信息如下
![使用Mybatis導致的OutOfMemoryError錯誤](http://p2.ttnews.xyz/loading.gif)
OutOfMemoryError
錯誤最終發生map的put上面,這個map是在UnknownTypeHandler的resolveTypeHandler方法中調用的。這個是現象,不是導致OutOfMemoryError的根本原因,但是這個方法確實會額外佔用一些內存。(根本原因是數據量突然增多,一次查出了上百萬的數據)
數據量大了這個方法也是挺佔用內存的,下面就先對這個方法分析:
這個方法首先獲取ResultSet的MataData,也就是每列的元數據,把這些信息組裝成一個map,通過傳入的列和這個map,確認當前列的位置。最後通過MataData和列的位置推斷出當前列的TypeHandler。如果查出的列很多,數據量很大的情況下這個臨時的map就有可能是壓死駱駝的最後一根稻草。
resolveTypeHandler
Mybatis的TypeHandler
說到UnknownTypeHandler,就先看看TypeHandler,mybaits在查詢出來的resultSet的每一列都會通過TypeHandler轉成Java需要的類型,這個就是類型轉換。Mybatis內置了很多的TypeHandler,如果框架提供的不能滿足需求,我們也可以自定義一個TypeHandler。如果部署下TypeHandler,請參考下文:
為什麼會用UnknownTypeHandler呢?
如果代碼走到了UnknownTypeHandler中,說明在程序啟動解析resultmap的時候沒有找到具體的TypeHanlder,只能藉助運行期間推斷出具體的TypeHanlder,這樣程序就會多執行很多代碼,影響了效率,也可能導致OOM的發生。
UnknownTypeHandler的註冊
初始化的時候,會在TypeHandlerRegistry中註冊所有的TypeHandler也包括UnknownTypeHandler,註冊了三種情況下使用UnknownTypeHandler。
- column的JavaType是Object
- column的JavaType是Object,JdbcType是OTHRE
- column的JdbcType是OTHRE
UnknownTypeHandler
除了以上,如果我們resultMap的type為java.util.Map,並且JavaType和typeHandler都沒有定義,此時框架推斷不出來具體的typeHandler,最終也會設置為UnknownTypeHandler。
如果resultMap的type為實體類,並且JavaType和typeHandler都沒有定義,如果設置了當前類的property屬性,框架推斷到property指定變量的set方法的類型。
下面是我測試用的一個resultmap,所有列的類型都會用UnknownTypeHandler解析。
resultmap
說了這麼多,總結一點:寫代碼的時候能明確就明確,少讓框架自動去推斷,推斷是有成本的代價的。
關鍵字: typeHandler resultmap 錯誤