🌔 1、如何理解缓存?
🌔 2、MyBatis 中的缓存是怎样的呢?
🌔 3、准备工作:
🌔 1、如何使用一级缓存?
🌔 2、假如我们想根据 id 查询汽车信息:
(1)在CarMapper接口中写一个方法
/**
* 根据 id 查询汽车信息
* @param id
* @return
*/
Car selectById(Long id);
(2)在 CarMapper,xml 映射文件中编写对应的SQL
(3)想要看出用没用一级缓存,重点在测试方法的编写
$A: 我们直接查询相同 id 的汽车信息
@Test
public void testSelectById(){SqlSession sqlSession = SqlSessionUtil.openSession();CarMapper mapper = sqlSession.getMapper(CarMapper.class);Car car = mapper.selectById(31L);System.out.println(car);Car car1 = mapper.selectById(31L);System.out.println(car1);sqlSession.close();
}
此处我们可以看到就执行了一条 select * from t_car where id = 31L
【这所以这里就出现了 Cache Hit Ratio 是因为我开启了二级缓存】
$B:因为我们这里用的是同一个接口实现类,如果不是一个,那么一级缓存还会有效吗?
@Test
public void testSelectById(){SqlSession sqlSession = SqlSessionUtil.openSession();CarMapper mapper1 = sqlSession.getMapper(CarMapper.class);CarMapper mapper2 = sqlSession.getMapper(CarMapper.class);Car car = mapper1.selectById(31L);System.out.println(car);Car car1 = mapper2.selectById(31L);System.out.println(car1);sqlSession.close();
}
运行结果是一样的,说明只要满足在一个SqlSession下,相同的查询语句就会使用一级缓存
$C: 我们最后再验证一下,如果不同的SqlSession,一级缓存是否还有效?
@Test
public void testSelectById() throws Exception{// 利用原始的创建会话的方法SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));// 创建两个会话SqlSession sqlSession1 = sqlSessionFactory.openSession();SqlSession sqlSession2 = sqlSessionFactory.openSession();// 创建对应的接口实现类CarMapper mapper1 = sqlSession1.getMapper(CarMapper.class);CarMapper mapper2 = sqlSession2.getMapper(CarMapper.class);// 调用查询方法Car car1 = mapper1.selectById(32L);Car car2 = mapper2.selectById(32L);System.out.println(car1);System.out.println(car2);sqlSession1.close();sqlSession2.close();
}
此处我们使用了SqlSessionFactory的openSession方法,这个方法每次调用都会创建一个新的连接对象
可以看出,不同的SqlSession对象之间是无法使用彼此的一级缓存的。
🌔 3、有哪些情况不会走一级缓存?
sqlSession.clearCache();
手动清理了缓存🌔 1、一级缓存与二级缓存的区别?
🌔 2、我们如何才能使用二级缓存?
】
🌔 3、演示我们是如何使用二级缓存的?
(1)接口方法
/**
* 测试二级缓存
* @param id
* @return
*/
Car selectById2(Long id);
(2)Mapper.xml 中添加catch标签和对应SQL
(3)接下来就是测试部分了:$A
– 没关闭连接,没使用二级缓存、$B
– 关闭连接了,使用了二级缓存
$A: 为了验证第二问第四点,我们第一个会话查询结束后先不关闭,第二个直接查询
@Test
public void testSelectById2() throws Exception{// 一个会话工厂SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));// 创建两个会话SqlSession sqlSession1 = sqlSessionFactory.openSession();SqlSession sqlSession2 = sqlSessionFactory.openSession();// 创建对应的接口实现类CarMapper mapper1 = sqlSession1.getMapper(CarMapper.class);CarMapper mapper2 = sqlSession2.getMapper(CarMapper.class);// 调用查询方法Car car1 = mapper1.selectById(32L);System.out.println(car1);// 我们没有关闭会话,所以不会将一级缓存写入到二级缓存Car car2 = mapper2.selectById(32L);System.out.println(car2);sqlSession1.close();sqlSession2.close();
}
通过结果我们可以看到,当我们不关闭前一个查询的连接,确实没有将一级缓存的内容写入二级缓存,底层还是执行了两次查询
$B: 这回我们执行完第一条查询就将这个会话关闭,看这次二级缓存中是否有数据
@Test
public void testSelectById2() throws Exception{// 一个会话工厂SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));// 创建两个会话SqlSession sqlSession1 = sqlSessionFactory.openSession();SqlSession sqlSession2 = sqlSessionFactory.openSession();// 创建对应的接口实现类CarMapper mapper1 = sqlSession1.getMapper(CarMapper.class);CarMapper mapper2 = sqlSession2.getMapper(CarMapper.class);// 调用查询方法Car car1 = mapper1.selectById(32L);System.out.println(car1);sqlSession1.close();// 我们没有关闭会话,所以不会将一级缓存写入到二级缓存Car car2 = mapper2.selectById(32L);System.out.println(car2);sqlSession2.close();
}
很明显可以看到,本次只执行了一次SQL语句
我们看到的 Cache Hit Ratio 第一条为 0,第二条为 0,5 是怎么回事儿呢?
首先这条语句代表的是二级缓存的命中率,第一次执行这条SQL,缓存中没有,所以就为零,然而第二次执行缓存中已经有了,所以命中率为两次执行命中一次,以此类推 2/3 …
🌔 4、二级缓存还可以进行一些自定义配置:
(1)引入依赖
org.mybatis.caches mybatis-ehcache 1.2.2
(2)在类的根路径下创建 ehcache.xml 【idea中就是resources目录下】
(3)在我们的映射文件中添加 catch 标签
(4)至此,我们指定的映射文件的二级缓存就替换成了 EhCache 的缓存【对一级缓存没有影响】