[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方法使用一级缓存**
![](https://box.kancloud.cn/9255576ce3648df837c07f75e427d5ad_628x84.png)
这个属性配置为true后, 会在查询数据前清空当前的一级缓存, 因此该方法每次都会重新从数据库中查询数据。但是由于这个方法清空了一级缓存, 会影响当前SqlSession中所有缓存的查询, 因此在需要反复查询获取只读数据的情况下, 会增加数据库的查询次数, 所以要避免这么使用。