Mybatis快取的那些事
今天寫程式碼的時候碰到了一個情況 簡單的的寫了一個小demo
@Test @Transactional public void test(){ Role role = new Role(); role.setRolename("xxxx"); int insert = roleMapper.insert(role); System.out.println(insert); Role roleBase = roleMapper.selectByPrimaryKey(role.getId()); System.out.println(roleBase); change(roleBase.getId(),"aaaa"); change(roleBase.getId(),"bbbb"); System.out.println(JSONUtils.toJSONString(roleBase)); } private void change(Integer roleId, String s){ Role role = roleMapper.selectByPrimaryKey(roleId); System.out.println(role); role.setRolename(s); }
對插入資料庫的一條資料做了一個change操作,但是並沒有傳入roleBase這個物件。
輸出:
通過觀察輸出,可以看出通過 selectByPrimaryKey 這個方法查出的物件是同一個物件,而且roleBase的值被改變了。
第一反應就是用了快取。
之後通過修改mybatis的配置
<settings>
<setting name="cacheEnabled" value="false"/>
</settings>
不啟用快取,但是查出來的資料依然是一樣的,還是同一個物件。
之後通過對selectByPrimaryKey打斷點,跟蹤執行的流程
這裡將資料快取進了localCache!!!
在網上找了一些cache相關的文章
local cache和cache
mybatis提供了兩種cache型別:local cache和cache
-
local cache,也就是所謂的區域性快取。由以下引數控制:
-
localCacheScope
,見相關文件
-
-
cache,也就是所謂的二級快取。由以下引數控制:
要特別注意的是,mybatis的local cache是無法關閉的。
那麼local cache幹了什麼?在預設配置情況下,mybatis會將同一session內的查詢結果都放在local cache中,這樣可以提高效能,避免每次都hit到資料庫。
那麼cache幹了什麼呢?和local cache相對的,cache是跨session的,也就是說這個session中快取的結果,在另外一個session中也能夠用到。
問題分析
前面已經講到了在同一session中的查詢會將結果快取,那麼這個和我們一開始提到的問題有什麼關係呢?聰明的你一定已經想到了,這個問題和啟用了事務有關。
實際上mybatis在和spring整合後,會自動將session繫結到事務上,那麼就會產生前面提到的問題。
解決辦法
有以下幾種解決辦法:
-
在mybatis配置檔案中
localCacheScope=STATEMENT
。 -
在mapper配置檔案中,給select設定
flushCache=true
。需要注意的是,這樣會將local cache和cache都清空掉。 -
不用事務
測試了1,3兩個方法可以結局localcache的問題。2應該也ok
學習可以學習美團點評對Mybatis的快取介紹,講的很詳細了。