一、一级缓存介绍
1、一级缓存(local cache),即本地缓存,作用域默认为 SqlSession。当 Session flush 或 close 后,该 session 中的所有 Cache 将被清空。
2、本地缓存不能被关闭,但可以调用 clearCache() 来清空本地缓存,或者改变缓存的作用域。
3、在 MyBatis3.1 之后,可以配置本地缓存的作用域,在 MyBatis.xml 中配置。
4、一级缓存是 sqlsession 级别的缓存。一级缓存是一直开启的,sqlsession级别的一个 map,与数据库同一次会话期间查询到的数据会放在本地缓存中。
多个一级缓存中的数据不能共用。
以后如果需要获取相同的数据,直接从缓存中获取,不必再去查询数据库。
5、一级缓存的工作机制
同一次会话期间只要查询过的数据都会保存在当前的 SqlSession 的一个 Map 中
key:hashCode+查询的 SqlId + 编写的 sql 查询语句 + 参数
二、一级缓存失效的四种情况
一级缓存失效情况(没有使用到当前一级缓存的情况,效果就是,还需要再向数据发送SQL)
1、sqlSession 不同:使用不同的 sqlSession 数据库会话,不同的 SqlSession 对应不同的一级缓存;
2、sqlSession 相同:但查询条件不同(当前一级缓存中还没有这个数据)
3、如果sqlSession相同:两次查询之间执行了增删改操作(这次增删改可能对当前数据有影响)
4、如果sqlSession相同,手动清除了一级缓存(把缓存内容清空)
SqlSession 级别的缓存就相当于一个 Map。
三、一级缓存演示
1、在同一个 SqlSession 中查询同一条记录
代码:
/**
* mybatis中的一级缓存默认开启,是SqlSession级别的
* 即同一个SqlSession对于一个sql语句,执行之后就会存储在缓存中,
* 下次执行相同的sql,直接从缓存中取
*/
@Test
public void testFirstLevelCache() throws IOException {
SqlSessionFactory sqlSessionFactory = getsqlSessionFactory();
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
EmployeeMapperCache mapper = sqlSession.getMapper(EmployeeMapperCache.class);
Employee emp01 = mapper.getEmpById(1);
System.out.println("emp01 = " + emp01);
//处理业务
Employee emp02 = mapper.getEmpById(1);
System.out.println("emp02 = " + emp02);
System.out.println(emp01 == emp02);
} finally {
sqlSession.close();
}
}
运行结果:
可以看出,查询的是同一条记录,但第一次是从数据库中查询的,有 SQL 语句,第二次查询是就是从 缓存(SqlSession)中获取的。
2、从不同的 SqlSession 中查询同一条记录
代码:
/**
* 失效情况1:从不同的 SqlSession 中查询同一条记录
* @throws IOException
*/
@Test
public void testFirstLevelCacheInvalid1() throws IOException {
SqlSessionFactory sqlSessionFactory = getsqlSessionFactory();
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
EmployeeMapperCache mapper = sqlSession.getMapper(EmployeeMapperCache.class);
Employee emp01 = mapper.getEmpById(1);
System.out.println("emp01 = " + emp01);
//处理业务
SqlSession sqlSession2 = sqlSessionFactory.openSession();
EmployeeMapperCache mapper2 = sqlSession2.getMapper(EmployeeMapperCache.class);
Employee emp02 = mapper2.getEmpById(1);
System.out.println("emp02 = " + emp02);
System.out.println(emp01 == emp02);
} finally {
sqlSession.close();
}
}
运行结果:
虽然查询的是同一条记录,但是从不同的 SqlSession 中获取的,都从数据库进行查询,并没有从缓存中获取。
3、sqlSession 相同,但查询条件不同
代码:
/**
* 失效情况2:sqlSession 相同:但查询条件不同
* @throws IOException
*/
@Test
public void testFirstLevelCacheInvalid2() throws IOException {
SqlSessionFactory sqlSessionFactory = getsqlSessionFactory();
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
EmployeeMapperCache mapper = sqlSession.getMapper(EmployeeMapperCache.class);
Employee emp01 = mapper.getEmpById(1);
System.out.println("emp01 = " + emp01);
//处理业务
Employee emp02 = mapper.getEmpById(3);
System.out.println("emp02 = " + emp02);
System.out.println(emp01 == emp02);
} finally {
sqlSession.close();
}
}
运行结果:
使用的是同一个 sqlSession 对象,但是查询条件不同,也没有用到缓存,因为缓存中就没有符合此查询条件的数据。
4、在通过一个 SqlSession 中,两次查询之间有 增删改操作
代码:
/**
* 失效情况3:在通过一个 SqlSession 中,两次查询之间有 增删改操作
* @throws IOException
*/
@Test
public void testFirstLevelCacheInvalid3() throws IOException {
SqlSessionFactory sqlSessionFactory = getsqlSessionFactory();
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
EmployeeMapperCache mapper = sqlSession.getMapper(EmployeeMapperCache.class);
Employee emp01 = mapper.getEmpById(1);
System.out.println("emp01 = " + emp01);
//处理业务
mapper.updateEmp(new Employee(3, "John", "1", "John@163.com"));
System.out.println("更新成功");
Employee emp02 = mapper.getEmpById(1);
System.out.println("emp02 = " + emp02);
System.out.println(emp01 == emp02);
} finally {
sqlSession.close();
}
}
运行结果:
还是从同一个 SqlSession 中查询同一条记录,但由于期间涉及了增删改操作,一级缓存就会失效。
5、在同一个 SqlSession 中,手动清空缓存
代码:
/**
* 失效情况4:在同一个 SqlSession 中,手动清空缓存
* @throws IOException
*/
@Test
public void testFirstLevelCacheInvalid4() throws IOException {
SqlSessionFactory sqlSessionFactory = getsqlSessionFactory();
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
EmployeeMapperCache mapper = sqlSession.getMapper(EmployeeMapperCache.class);
Employee emp01 = mapper.getEmpById(1);
System.out.println("emp01 = " + emp01);
//处理业务
sqlSession.clearCache();
Employee emp02 = mapper.getEmpById(1);
System.out.println("emp02 = " + emp02);
System.out.println(emp01 == emp02);
} finally {
sqlSession.close();
}
}
运行结果:
虽然是在同一个 SqlSession 中进行查询的同一条记录,但由于在两次查询期间清空了缓存,还需要重新从数据库查询。