mybatis缓存
什么是缓存
存在于内存中的临时数据。
为什么要使用缓存呢
减少和数据库的交互次数,提高执行效率。
什么样的数据能使用缓存,什么样的数据不能使用
适用于缓存:
1.经常查询并且不经常改变的。
2.数据的正确与否对最终结果影响不大的。
不适用于缓存:
1.经常改变的数据
2.数据的正确与否对最终结果影响很大的。例如:商品的库存,银行的汇率,股市的牌价。
Mybatis中的一级缓存和二级缓存
一级缓存:
它指的是Mybatis中SqlSession对象的缓存。
当我们执行查询之后,查询的结果会同时存入到SqlSession为我们提供一块区域中。
该区域的结构是一个Map。当我们再次查询同样的数据,mybatis会先去sqlsession中查询是否有,有的话直接拿出来用。
当SqlSession对象消失时,mybatis的一级缓存也就消失了。
@Test
public void testFirstLevelCache() {
User user1 = userDao.findById(41);
System.out.println(user1);
User user2 = this.userDao.findById(41);
System.out.println(user2);
System.out.println(user1 == user2);//true
}
现在有这么一个测试方法,使用mybatis去查询user
发现两次查询的user1和user2是同一个对象,而且在第二次查询时,它没有再次去执行sql语句,而是直接输出结果了,原因就是因为mybatis中的sqlSession一级缓存机制。
只要 SqlSession 没有 flush 或 close,它就存在。
我们稍微做一些改变再次测试:
@Test
public void testFirstLevelCache() {
User user1 = userDao.findById(41);
System.out.println(user1);
sqlSession.close();
//再次获取sqlSession对象
sqlSession = factory.openSession();
// sqlSession.clearCache();//此方法也可以清空缓存
userDao = sqlSession.getMapper(UserDao.class);
User user2 = this.userDao.findById(41);
System.out.println(user2);
System.out.println(user1 == user2);//false
}
当我们中途close了一次sqlSession之后,就会发现,此时输出的是false,说明不再是同一个对象了,而且在第二次查询时重新执行了一次sql语句。
二级缓存:
它指的是Mybatis中SqlSessionFactory对象的缓存。由同一个SqlSessionFactory对象创建的SqlSession共享其缓存。
二级缓存的使用步骤:
第一步:让Mybatis框架支持二级缓存(在配置文件Config.xml中配置)
<!--配置参数-->
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
第二步:让当前的映射文件支持二级缓存(在持久层配置文件UserDao.xml中配置)
<!--开启user支持二级缓存-->
<cache/>
第三步:让当前的操作支持二级缓存(在select标签中配置)
<select id="findById" resultType="user" parameterType="int" useCache="true">
select * from USER where id = #{id}
</select>
测试二级缓存:
@Test
public void testFirstLevelCache() {
SqlSession sqlSession1 = factory.openSession();
UserDao userDao1 = sqlSession1.getMapper(UserDao.class);
User user1 = userDao1.findById(41);
System.out.println(user1);
sqlSession1.close();//一级缓存消失
SqlSession sqlSession2 = factory.openSession();
UserDao userDao2 = sqlSession2.getMapper(UserDao.class);
User user2 = userDao2.findById(41);
System.out.println(user2);
sqlSession2.close();
System.out.println(user1 == user2);//false
}
因为二级缓存存储的是Map结构的数据而不是对象,每次需要数据时,就会把缓存里面的数据拿出来给新的对象,所以此时也是两个不同对象输出也是false。
但是我们发现,经过上面的测试,执行了两次查询,并且在执行第一次查询后,我们关闭了一级缓存,再去执行第二次查询时,我们发现并没有对数据库发出 sql 语句,所以此时的数据就只能是来自于我们所说的二级缓存。