摘要:今天對(duì)象在學(xué)習(xí)時(shí)發(fā)現(xiàn)對(duì)象的方法并不能清理一級(jí)緩存同一下相同查詢條件返回的結(jié)果還是舊值。測(cè)試代碼如下上網(wǎng)搜索網(wǎng)上搜索找到了相同問題并沒有人解答。例如查看官方文檔實(shí)例有一個(gè)本地緩存在執(zhí)行和時(shí)被清理。要明確地關(guān)閉它獲取打算做更多的工作你可以調(diào)用。
今天對(duì)象在學(xué)習(xí) Mybatis 時(shí)發(fā)現(xiàn) org.apache.ibatis.session.SqlSession 對(duì)象的 clearCache() 方法并不能清理一級(jí)緩存, 同一 session 下相同查詢條件返回的結(jié)果還是舊值。測(cè)試代碼如下
上網(wǎng)搜索網(wǎng)上搜索找到了相同問題, 并沒有人解答。例如:https://www.iqismart.com/topi...
查看官方文檔http://www.mybatis.org/mybati...
SqlSession 實(shí)例有一個(gè)本地緩存在執(zhí)行 update,commit,rollback 和 close 時(shí)被清理。要明確地關(guān)閉它(獲取打算做更多的工作) ,你可以調(diào)用 clearCache()。
看起來, 沒什么問題, 方法也沒有被標(biāo)記成廢棄.
打印詳細(xì)日志先把日志配上, 看看有沒有打印什么有用的信息, 添加 slf4j、logback 依賴,添加 logback.xml , 日志級(jí)別設(shè)置為 DEBUG 運(yùn)行后未看到跟清理緩存有關(guān)的信息, 調(diào)整日志級(jí)別為 TRACE 后依舊沒有.
看 clearCache() 源碼mybatis %d{HH:mm:ss.SSS} [%thread] %-5level %logger %msg%n mybatis.log UTF-8 %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
上面方法都沒有收獲, 只能看源碼了.第一步, 先看一下 clearCache() 做了什么, 下面會(huì)大規(guī)模貼圖
注意 PerpetualCache 類的 cache 變量
org.apache.ibatis.cache.impl.PerpetualCache#cache 就是一個(gè) HashMap
到此, clearCache() 已經(jīng)完結(jié), 最終就是調(diào)用一個(gè) HashMap 的 clear() 方法
看 selectOne() 源碼
這一步?jīng)]有什么好看的, 就是封一層 selectList
第一個(gè)方法會(huì)間接調(diào)用第二個(gè), 只是少了一個(gè)分頁相關(guān)的 RowBounds
把傳入的 statement 值變成 MappedStatement, 由于不是我們查看源碼的重點(diǎn), 可以直接跳過.
不過可以學(xué)習(xí)到 Mybatis 其實(shí)是把我們寫的 xml 文件抽象成 MappedStatement , 在執(zhí)行 sql 時(shí)需要先使用 statement (也就是我們 xml 中 select 標(biāo)簽中的 id) 去配置中 get 出整個(gè) MappedStatement, MappedStatement 包含了 resultMaps 之類的, 一會(huì)兒 sql 返回時(shí)映射結(jié)果集很可能要用到.
這一步把 MappedStatement 變成 BoundSql, BoundSql 應(yīng)該就是每條 SQL 的抽象.
還會(huì)根據(jù) MappedStatement (xml 文件)、parameter (sql 參數(shù))、rowBounds (分頁信息)、BoundSql (SQL) 生成一個(gè) CacheKey (緩存 key) .
已經(jīng)跟我們想要了解的東西沾點(diǎn)邊了.
這一步是取 MappedStatement 對(duì)象的 Cache , 暫時(shí)不知道是什么緩存(可能是二級(jí)緩存), 可以知道的是和剛才看 clearCache() 清理的不是同一個(gè)東西. 調(diào)試發(fā)現(xiàn)返回值是 null, 不關(guān)心繼續(xù)往下看
這里到了 BaseExecutor 類, 152 行會(huì)根據(jù) CacheKey 從 localCache 獲取結(jié)果.
而且和 clearCache() 方法清理的是同一個(gè)緩存對(duì)象.
基本可以確定 Mybatis 就是在這里從一級(jí)緩存獲取結(jié)果后返回, 需要重點(diǎn)關(guān)注.
反復(fù)運(yùn)行發(fā)現(xiàn)如下規(guī)律:
如果第二次查詢前不加 sqlSession.clearCache(); 可以從 localCache get 出結(jié)果
如果第二次查詢前加 sqlSession.clearCache(); localCache get 結(jié)果為空
由此可以得出結(jié)論:
sqlSession.clearCache() 方法是有效的, 清理一級(jí)緩存后第二次查詢結(jié)果依然和第一次相同, 和 Mybatis 一級(jí)緩存并無關(guān)系.
既然如此, 要想知道結(jié)果, 只能繼續(xù)往下跟蹤, 看一級(jí)緩存為空后, Mybatis 是怎么處理的.
可以看出, 為空后調(diào)用了 queryFromDatabase 方法,從方法名可以理解, 會(huì)去數(shù)據(jù)庫查詢
第 322 行先往一級(jí)緩存設(shè)置一個(gè)占位符, 并無實(shí)際含義
第 324 行執(zhí)行查詢動(dòng)作, 需要重點(diǎn)關(guān)注
第 326 行根據(jù)緩存 key 清理一級(jí)緩存
第 328 行重新設(shè)置一級(jí)緩存
第 330 行看到一個(gè)面熟的東西, 在 clearCache() 時(shí)會(huì)同時(shí)清理 localCache 和 localOutputParameterCache, 如果執(zhí)行的是存儲(chǔ)過程, 會(huì)把參數(shù)緩存起來
繼續(xù)跟蹤 doQuery 方法
先是獲取 MappedStatement 的配置, 創(chuàng)建一個(gè) StatementHandler, 加工成 JDBC 標(biāo)準(zhǔn)的 Statement , 這中間隱藏了無數(shù)細(xì)節(jié), 還是那句話, 不是我們關(guān)心的重點(diǎn), 繼續(xù)跟蹤 Query 方法
經(jīng)過 RoutingStatementHandler 路由分發(fā), 到達(dá) SimpleStatementHandler
方法體只有三行
第一行拿出具體 SQL
第二行調(diào)用 statement.execute() 方法, 這里已經(jīng)到了 JDBC 驅(qū)動(dòng)層, mysql 驅(qū)動(dòng)包會(huì)幫我們封裝請(qǐng)求包發(fā)送給 mysql 服務(wù)器并把響應(yīng)結(jié)果映射到 jdbc 規(guī)范的對(duì)象中
第三行處理返回結(jié)果集
其實(shí)執(zhí)行完 execute 方法, 就可以從 PreparedStatement 對(duì)象 get 出想要的結(jié)果集, 但貿(mào)然 get 會(huì)影響 Mybatis 處理, 還是繼續(xù)跟蹤 handleResultSets 方法吧
方法一開始聲明了一個(gè) multipleResults , 這個(gè)就是最終的結(jié)果集.
接著分別處理 ResultMap 和 ResultSet, 把 mysql 返回的結(jié)果按照 xml 中的規(guī)則映射成指定對(duì)象
由于 xml 中的 select 并沒有定義 resultSets , 只關(guān)注上半部分即可, 斷點(diǎn)設(shè)在 198 行
可以看出 mysql 服務(wù)器返回的確實(shí)是舊值,
階段性成果至此可以確定一級(jí)緩存清理無效的問題和應(yīng)用沒有關(guān)系.
還能是什么問題呢, 難道是事務(wù)的隔離級(jí)別導(dǎo)致的, 應(yīng)用只是簡單的查詢, 連事務(wù)管理器都沒有配置, 要有問題也只能懷疑 mysql 服務(wù)器.
查詢數(shù)據(jù)庫的默認(rèn)隔離級(jí)別
mysql> SELECT @@global.tx_isolation; +-----------------------+ | @@global.tx_isolation | +-----------------------+ | REPEATABLE-READ | +-----------------------+ 1 row in set, 1 warning (0.00 sec) mysql> SELECT @@session.tx_isolation; +------------------------+ | @@session.tx_isolation | +------------------------+ | REPEATABLE-READ | +------------------------+ 1 row in set, 1 warning (0.00 sec) mysql> SELECT @@tx_isolation; +-----------------+ | @@tx_isolation | +-----------------+ | REPEATABLE-READ | +-----------------+ 1 row in set, 1 warning (0.00 sec)
竟然是"可重復(fù)讀", 好了, 原因找到, 此貼終結(jié).
解決解決辦法就是把事務(wù)的默認(rèn)隔離級(jí)別設(shè)置成 "讀已提交".
mysql> SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; Query OK, 0 rows affected (0.00 sec) mysql> SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED; Query OK, 0 rows affected (0.00 sec)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/68361.html
摘要:一級(jí)緩存介紹及相關(guān)配置。在這個(gè)章節(jié),我們學(xué)習(xí)如何使用的一級(jí)緩存。一級(jí)緩存實(shí)驗(yàn)配置完畢后,通過實(shí)驗(yàn)的方式了解一級(jí)緩存的效果。源碼分析了解具體的工作流程后,我們隊(duì)查詢相關(guān)的核心類和一級(jí)緩存的源碼進(jìn)行走讀。 我,后端Java工程師,現(xiàn)在美團(tuán)點(diǎn)評(píng)工作。愛健身,愛技術(shù),也喜歡寫點(diǎn)文字。個(gè)人網(wǎng)站: http://kailuncen.me公眾號(hào): KailunTalk (凱倫說) 前言 本文主要涉及...
摘要:一級(jí)緩存介紹及相關(guān)配置。在這個(gè)章節(jié),我們學(xué)習(xí)如何使用的一級(jí)緩存。一級(jí)緩存實(shí)驗(yàn)配置完畢后,通過實(shí)驗(yàn)的方式了解一級(jí)緩存的效果。源碼分析了解具體的工作流程后,我們隊(duì)查詢相關(guān)的核心類和一級(jí)緩存的源碼進(jìn)行走讀。 我,后端Java工程師,現(xiàn)在美團(tuán)點(diǎn)評(píng)工作。愛健身,愛技術(shù),也喜歡寫點(diǎn)文字。個(gè)人網(wǎng)站: http://kailuncen.me公眾號(hào): KailunTalk (凱倫說) 前言 本文主要涉及...
摘要:問題線上定時(shí)任務(wù)計(jì)算出的金額不對(duì)定位問題查看日志好像也執(zhí)行了但是金額為什么和數(shù)據(jù)庫的表里的不一致再查整個(gè)的定時(shí)任務(wù)日志日切日期 問題: 線上riskProvision定時(shí)任務(wù),計(jì)算出的金額不對(duì) 定位問題: 查看日志 4.13 riskProvision 2017-04-13 01:10:00.009 [org.springframework.scheduling.quartz....
摘要:今天整理了一下近大半年以來的一些文章,和我的預(yù)期一樣,很多文章我都忘記自己曾經(jīng)寫過了,這個(gè)記錄的過程讓我也有了新的理解。希望大家,收藏,點(diǎn)贊,加轉(zhuǎn)發(fā)。 今天整理了一下近大半年以來的一些文章,和我的預(yù)期一樣,很多文章我都忘記自己曾經(jīng)寫過了,這個(gè)記錄的過程讓我也有了新的理解。希望大家,收藏,點(diǎn)贊,加轉(zhuǎn)發(fā)。 面試必備 面試必備:深入Spring MVC DispatchServlet 源碼...
閱讀 4527·2021-09-09 09:33
閱讀 2414·2019-08-29 17:15
閱讀 2402·2019-08-29 16:21
閱讀 1004·2019-08-29 15:06
閱讀 2640·2019-08-29 13:25
閱讀 599·2019-08-29 11:32
閱讀 3278·2019-08-26 11:55
閱讀 2617·2019-08-23 18:24