缓存通过减少IO(读写文件)的方式,来提高程序的执行效率。mybatis的缓存将select语句的查询结果放到缓存(内存)当中,下一次还是这条select语句的话,直接从缓存中取,不再查数据库。一方面是减少了IO,另一方面不再执行繁琐的查找算法,效率大大提升。
mybatis缓存包括:
缓存只针对于DQL语句,也就是说缓存机制只对应select语句
默认开启,同一个SqlSesion级别共享的缓存,在一个SqlSession的生命周期内,如果执行2次相同的SQL查询,那么第二次SQL查询会直接取缓存的数据,而不是到数据库中查询,当然,若第一次和第二次相同的SQL查询之间,执行了DML(INSERT/UPDATE/DELETE),则一级缓存会被清空,第二次查询相同SQL仍然会到数据库中查找数据。
一级缓存在下面情况会被清除
MappedStatement是指:一个CRUD标签在mybatis中会被封装成一个MappedStatement。
测试
mapper接口:
//通过id查询汽车
Car selectById(Long id);
mapper映射文件:
测试类: 使用的是同一个mapper
//测试一级缓存
@Test
public void test1(){
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
Car car1 = mapper.selectById(194L);
System.out.println(car1);
Car car2 = mapper.selectById(194L);
System.out.println(car2);
//关闭
sqlSession.close();
}
测试结果:
执行相同的sql的时候,第二次没有执行sql语句,而是直接使用缓存!
换换测试方式:既然是在同一个sqlsession那么和创建的mapper应该没有什么关系吧
//使用的是不同mapper(狗头保命sqlsession)
@Test
public void test2(){
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
Car car1 = mapper.selectById(194L);
System.out.println(car1);
Car car2 = mapper.selectById(194L);
System.out.println(car2);
//关闭
sqlSession.close();
}
测试结果 还是一个
获取不同的Sqlsession对象测试:
@Test
public void test3() throws IOException {
SqlSessionFactoryBuilder sqlSessionFactoryBuilder=new SqlSessionFactoryBuilder();
SqlSessionFactory sessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsReader("mybatis-config.xml"));
SqlSession sqlSession = sessionFactory.openSession();
SqlSession sqlSession1 = sessionFactory.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
Car car = mapper.selectById(194L);
System.out.println(car);
CarMapper mapper1 = sqlSession1.getMapper(CarMapper.class);
Car car1 = mapper1.selectById(194L);
System.out.println(car1);
sqlSession.close();
sqlSession1.close();
}
测试的结果是使用的是两个sqlsession对象,所以导致这样的情况发生。由于只会存在同一个SQL Session的缓存,所以此次的查询使用啦两个sql语句。
默认关闭,可通过全局配置文件中的
使用二级缓存需要具备以下几个条件:
1、
2、在需要使用二级缓存的SqlMapper.xml文件中添加配置:
3、使用二级缓存的实体类对象必须是可序列化的,也就是必须实现java.io.Serializable接口
4、SqlSession对象关闭或提交之后,一级缓存中的数据才会被写入到二级缓存当中。此时二级缓存才可用。
测试类:
@Test
public void test4() throws IOException {
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis-config.xml"));
SqlSession sqlSession = sessionFactory.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
Car car = mapper.selectById2(194L);
System.out.println(car);
SqlSession sqlSession1 = sessionFactory.openSession();
CarMapper mapper1 = sqlSession1.getMapper(CarMapper.class);
Car car1 = mapper1.selectById2(194L);
System.out.println(car1);
}
这里避免了一级缓存的情况,使用的不同sqlSession对象,但是没有关闭和提交所以应该是两条的sql语句。
测试结果:
执行的是两个sql语句!
那么将上面的测试的代码稍稍稍修改一下,然后体现二级缓存的功能!
测试结果: