[TOC]
*****
使用緩存可以使應用更快地獲取數據, 避免頻繁的數據庫交互,尤其是在查詢越多、 緩存命中率越高的情況下, 使用緩存的作用就越明顯。
# 7.1 一級緩存
mybatis默認啟動一級緩存(本地緩存) ,一級緩存可以產生一些難以發現的錯誤。
**1 在CacheTest.java文件中**
```
public class CacheTest extends BaseMapperTest {
@Test
public void testL1Cache(){
//獲取 sqlSession
SqlSession sqlSession = getSqlSession();
SysUser user1 = null;
try {
//獲取 UserMapper 接口
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//調用 selectById 方法,查詢 id = 1 的用戶
user1 = userMapper.selectById(1l);
//對當前獲取的對象重新賦值
user1.setUserName("New Name");
//再次查詢獲取 id 相同的用戶
SysUser user2 = userMapper.selectById(1l);
//沒有更新數據庫,但是user2的用戶名和我們 user1的用戶名字相同
Assert.assertEquals("New Name", user2.getUserName());
//user2 和 user1 完全就是同一個實例
Assert.assertEquals(user1, user2);
} finally {
//關閉當前的 sqlSession
sqlSession.close();
}
System.out.println("開啟新的 sqlSession");
//開始另一個新的 session
sqlSession = getSqlSession();
try {
//獲取 UserMapper 接口
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//調用 selectById 方法,查詢 id = 1 的用戶
SysUser user2 = userMapper.selectById(1l);
//user2的用戶名和我們 user1的用戶名字不相同,user2用戶名還是admin(表中的數據值)
Assert.assertNotEquals("New Name", user2.getUserName());
//這里的user2 和 user1不是同一個實例
Assert.assertNotEquals(user1, user2);
//執行刪除操作
userMapper.deleteById(2L);
//獲取 user3
SysUser user3 = userMapper.selectById(1l);
//這里的 user2 和 user3 是兩個不同的實例
Assert.assertNotEquals(user2, user3);
} finally {
//關閉 sqlSession
sqlSession.close();
}
}
}
```
**第一個try塊**
MyBatis的一級緩存存在于 SqlSession的生命周期中, 在同一個SqlSession中查詢(SELECT)時, MyBatis會把執行的方法和參數通過算法生成緩存的鍵值, 將鍵值和查詢結果存入一個Map對象中。
如果同一個 SqlSession中執行的方法和參數完全一致, 那么通過算法會生成相同的鍵值。 當使用相同參數執行同一個方法時, 根據Map緩存對象中已經存在的鍵值返回緩存中的對象。所以第一個try塊中的user1和user2是同一個實例,修改user1會影響user2。
**第二個try塊**
在關閉第一個 SqlSession 后, 又重新獲取了一個 SqlSession, 因此 又重新查詢了user2, 這時在日志中輸出了數據庫查詢SQL, user2是一 個新的實例, 和user1沒有任何關系。 這是因為**一級緩存是和SqlSession 綁定的, 只存在于SqlSession的生命周期中。**
接下來執行了一個deleteById操作, 然后使用相同的查詢方法和參數獲 取了user3實例, 從日志和結果來看, user3 和 user2 也是完全不同的兩 個對象。 這是因為**任何的 INSERT、 UPDATE、 DELETE操作都會清空一級緩存**, 所以查詢user3的時候由于緩存不存在, 就會再次執行數據庫查詢獲取數據。
**不讓selectById方法使用一級緩存**

這個屬性配置為true后, 會在查詢數據前清空當前的一級緩存, 因此該方法每次都會重新從數據庫中查詢數據。但是由于這個方法清空了一級緩存, 會影響當前SqlSession中所有緩存的查詢, 因此在需要反復查詢獲取只讀數據的情況下, 會增加數據庫的查詢次數, 所以要避免這么使用。