1. 程式人生 > >mybaties的緩存(轉)

mybaties的緩存(轉)

exception hiberna 通過 cti pan 問題 -- name namespace

內容大綱.png

前言

本篇意在通過Hibernate和Mybaitis緩存,通過對比學習,同時弄懂這兩者中的區別

Hibernate中的緩存

Hibernate中一般常用的緩存有三個,一級緩存,二級緩存,查詢緩存,要了解一二級緩存的可以點擊->圖解SSH-Hibernate,這裏主要講解一下二級緩存和查詢緩存

首先我們先看一下Hibernate的二級緩存

技術分享
Hibernate二級緩存.png

文字描述過程:

  • 首先我們get(1L)的時候,由於二級緩存中沒有,所以我們就去數據庫查詢,並將結果返回後插入到二級緩存中,然後將結果插入到二級緩存中,並將數據返回.

  • 當我們再次查詢時,由於二級緩存

    中已經存在了該對象,那麽我們就不用到數據庫中查詢,直接從緩存中把結果返回

那麽我們再來看看Hibernate中的查詢緩存

技術分享
Hibernate查詢緩存.png

文字描述過程:

  • 首先list()的時候,由於查詢緩存中沒有,那麽我們去數據庫查,並將數據放在了查詢緩存中,然後將結果返回

  • 當我們進行insert操作的時候,首先會給數據庫增加一條數據,然後關鍵的地方來了,此時Hibernate會清空所有的查詢緩存,因為此時數據庫中的數據已經變了,如果不清空緩存,就會導致select * from User拿到的還是1L和2L,但是此時正確的應該是1L,2L,3L,所以必須清空

  • 然後我們再次list()

    的時候,又重復第一步的操作

從以上過程我們就可以看出,Hibernate的查詢緩存的命中率的非常低的,進行新增、編輯、刪除操作都會去清空查詢緩存,所以一般不使用查詢緩存,而是使用二級緩存.

Mybaitis中的緩存

一般我們都不說MyBatis的二級緩存,而是說MyBatis的緩存,我們先來看代碼

@Test
public void testCache() throws Exception {

    SqlSession session = MybatisUtil.openSession();
    UserMapper userMapper = session.getMapper(UserMapper.class);
    User u1 = userMapper.get(1L);
    session.close();

    session = MybatisUtil.openSession();
    userMapper = session.getMapper(UserMapper.class);
    User u2 = userMapper.get(1L);
    session.close();
}

這段代碼中, Mybatis一共發了兩條SQL,這就好像說, Mybatis中沒有二級緩存,然後我們打開Mybatis的文檔一看,頓時震驚

技術分享
Mybatis文檔.png

這難道是騙人的,說好的默認開啟緩存呢.....

其實不是的,默認確實是開啟緩存的,但是我們還需要配置一點東西

UserMapper.xml

<mapper namespace="com.toby.mybatis.domain.UserMapper">
    <!--mybatis中默認是支持二級緩存的,
    要是某個對象由二級緩存,需要在mapper.xml中配置如下標簽-->
    <cache/>
    ...
</mapper>

另外,對象還要實現序列化接口,否則報NotSerializableException的異常

public class User implements Serializable{
...
}

設置完畢之後,我們再來嘗試insert的問題

@Test
public void testCache() throws Exception {

    SqlSession session = MybatisUtil.openSession();
    UserMapper userMapper = session.getMapper(UserMapper.class);
    User u1 = userMapper.get(1L);
    session.close();

    //insert
    session = MybatisUtil.openSession();
    userMapper = session.getMapper(UserMapper.class);
    User user = new User();
    userMapper.add(user);
    session.commit();
    session.close();

    session = MybatisUtil.openSession();
    userMapper = session.getMapper(UserMapper.class);
    User u2 = userMapper.get(1L);
    session.close();
}

此時發現,發了3條SQL,那麽究竟是什麽原因呢?

首先,get的底層用的是selectOne,然後selectOne又用的是用selectList,所以Mybatis是沒有二級緩存的概念,他的緩存,全都是查詢緩存.此時如下圖

技術分享
Mybatis緩存.png

看完這個圖,就明白為什麽get(1L)->add()->get(1L)這個過程會發3條SQL了,因為insert的時候,清空了緩存

但是就算insert,並沒有影響到get(1L)的結果,但是你卻把他的緩存也清空了,這明顯不合理,那麽我們怎麽樣讓Mybatis中的緩存更像Hibernate中的二級緩存呢?因為目前這樣的緩存實在太坑,從這過程大家應該感受得到.

那麽我們可不可以這樣做呢?如圖:

技術分享
mybatis緩存改進.png

也就是我們做了兩件事

  • list由於緩存命中率低,那麽我們就不加入到緩存中

  • insert我們不清空緩存

這樣做,Mybatis的緩存就顯得更像Hibernate中的二級緩存了,那麽在代碼中,我們具體是怎麽實現的呢?

UserMapper.xml

<!--useCache默認是true,這裏我們設置為false就是讓他不使用緩存-->
<select id="list" resultType="com.toby.mybatis.domain.User" useCache="false">
  SELECT * FROM user
</select>

<!--flushCache默認為true,我們設置為false,就是讓他不清空緩存-->
<insert id="add" parameterType="com.toby.mybatis.domain.User"
        useGeneratedKeys="true" keyProperty="id" keyColumn="id" 
        flushCache="false">
    INSERT INTO USER (username) VALUES (#{username})
</insert>

這樣之後,我們Mybatis中的緩存就更高效了

mybaties的緩存(轉)