---
# System prepended metadata

title: 二級緩存
tags: [Mybatis-緩存]

---

# 二級緩存
###### tags: `Mybatis-緩存`

* 二級緩存也被稱作全局緩存，一級緩存作用域太低了，所以誕生了二級緩存
* 基於namespace級別的緩存，一個空間名稱，對應一個二級緩存;

**工作機制**

* 一個會話查詢一條數據，這個數據就會被放在當前會話的一級緩存中
* 如果當前會話關閉了，這個會話對應的一級緩存就沒了；但是我們想要的式，會話關閉了，一級緩存中的數據被保存到二級緩存中
* 新的會話查詢信息，就可以從二級緩存中獲取內容
* 不同的mapper查出的數據會放在自己對應的緩存(map)中

默认情况下，只启用了本地的会话缓存，它仅仅对一个会话中的数据进行缓存。 要启用全局的二级缓存，只需要在你的 SQL 映射文件中添加一行： 
```xml=
<cache/>
```

### 步驟：
1.開啟全局緩存
```xml=
    <settings>
        <!--顯式開啟全局緩存-->
        <setting name="cacheEnabled" value="true"/>
    </settings>
```

2.在要使用二級緩存的Mapper中開啟
```xml=
<cache/>
```

也可以自定義參數
```xml=
    <!--在當前Mapper.xml中使用二級緩存-->
    <cache  eviction="FIFO"
            flushInterval="60000"
            size="512"
            readOnly="true"/>
```
也可以在各別方法中設置
```xml=
    <!--useCache：也可以在個別方法中設置-->
    <select id="queryUserById" resultType="User" useCache="true">
        select * from user where id = #{id}
    </select>
```

3.測試

(1)二級緩存的應用
```java=
    @Test
    public void test(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.queryUserById(1);
        System.out.println(user);
        //需要先關閉，讓緩存保存到二級緩存中
        //讓下方的相同mapper查詢相同資料時，直接就可以到二級緩存中取用
        sqlSession.close();

        SqlSession sqlSession2 = MybatisUtils.getSqlSession();
        UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
        User user2 = mapper2.queryUserById(1);
        System.out.println(user2);

        System.out.println(user == user2);

        sqlSession2.close();
    }
```
![](https://i.imgur.com/dfqky9e.png)

(2)二級緩存的失敗
因為尚未相關第一個sqlsession，導致查詢的資料沒有保存到二級緩存中，造成第二次要重新查詢
```java=
    @Test
    public void test(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.queryUserById(1);
        System.out.println(user);
        //需要先關閉，讓緩存保存到二級緩存中
        //讓下方的相同mapper查詢相同資料時，直接就可以到二級緩存中取用

        SqlSession sqlSession2 = MybatisUtils.getSqlSession();
        UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
        User user2 = mapper2.queryUserById(1);
        System.out.println(user2);

        System.out.println(user == user2);
        //第一次sqlSession關閉前，就開始第二次sqlSession的查詢，導致緩存沒有保留到二級緩存池中，因此sqlSession2要重新查詢
        sqlSession.close();
        sqlSession2.close();
    }
```
![](https://i.imgur.com/tEh3D2O.png)

1.問題：我們需要將實體類序列化，否則就會報錯
```java=
public class User implements Serializable {
    private int id;
    private String name;
    private String pwd;
}
```

### 小結：
1. 只要開啟了二級緩存，在同一個mapper下就有效
2. 所有的數據都會先放在一級緩存中；
3. 只有當會話提交或關閉的時候，才會提交到二級緩存中