1. 程式人生 > >Mybatis快取的那些事

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

要特別注意的是,mybatis的local cache是無法關閉的。

那麼local cache幹了什麼?在預設配置情況下,mybatis會將同一session內的查詢結果都放在local cache中,這樣可以提高效能,避免每次都hit到資料庫。

那麼cache幹了什麼呢?和local cache相對的,cache是跨session的,也就是說這個session中快取的結果,在另外一個session中也能夠用到。

問題分析

前面已經講到了在同一session中的查詢會將結果快取,那麼這個和我們一開始提到的問題有什麼關係呢?聰明的你一定已經想到了,這個問題和啟用了事務有關。

實際上mybatis在和spring整合後,會自動將session繫結到事務上,那麼就會產生前面提到的問題。

解決辦法

有以下幾種解決辦法:

  1. 在mybatis配置檔案中localCacheScope=STATEMENT

  2. 在mapper配置檔案中,給select設定flushCache=true。需要注意的是,這樣會將local cache和cache都清空掉。

  3. 不用事務

測試了1,3兩個方法可以結局localcache的問題。2應該也ok

學習可以學習美團點評對Mybatis的快取介紹,講的很詳細了。