一,Mybatis中为什么要有缓存
缓存的意义是将用户经常查询的数据放入缓存(内存)中去,用户去查询数据的时候就不需要从磁盘(关系型数据库)中查询,直接从缓存中查询,从而提高了查询效率,解决了高并发中系统的性能问题。Mybatis中提供一级缓存与二级缓存。
Mybatis的一级缓存是一个SqlSession级别的缓存,只能访问自己的一级缓存数据,而二级缓存是Mapper级别的缓存,是跨SqlSession的,不同的SqlSession是可以共享缓存数据的。
二,一级缓存
Mybatis 一级缓存原理:
第一次发出查询请求,sql 查询的结果写入SqlSession的一级缓存当中,缓存使用的数据结构是一个map<key, value>
key : hashcode + sql + sql输入参数 + 输出参数 (sql的唯一标识)
value : 用户信息
同一个SqlSession再次发出相同的sql,就会从缓存中读取而不走数据库,如果两次操作之间出现commit(修改、输出、添加)操作,那么本SqlSession中一级缓存区域全部清空,下次再去缓存中查不到所以要从数据库中查询,从数据库再写入一级缓存。
@Test
public void createTable(){
SqlSession sqlSession = DBUtil.getSqlSession();
List<Map<String, Object>> list1 = sqlSession.selectList("com.snow.xml.SnowOracle.getEmployeeByName", "周康");
System.out.println(list);
List<Map<String, Object>> list2 = sqlSession.selectList("com.snow.xml.SnowOracle.getEmployeeByName", "周康");
System.out.println(list2);
}
在数据库中有一张Employee表,里面有一条数据,通过selectList的方法查询,结果如下[{ID=70DD7D10-9FC6-4B79-ADAF-8B408DE1E048, EMPNAME=周康, AGE=36, DMGRP=男, BIRTHDATE=1987-07-31 00:00:00.0, SALARY=17000, ADDRESS=湖南长沙, GRADE=高级架构师}]
此时,手动修改数据库该人的年龄,手动修改为35,然后保存
此时,在运行代码,查看list2的值,两次结果一致,都是36 并非 35,说明第二次相同的查询走的是SqlSession中的一级缓存。
Mybatis 中一级缓存需要注意的点 :
Mybatis 中一级缓存是默认开启的,不需要手动配置。
Mybatis 和 Spring 整合后进行 mapper 代理开发后,不支持一级缓存。Mybatis 和 Spring 整合,Spring 按照 mapper 的模板去生成 mapper 代理对象,模板中在最后会统一关闭 SqlSession。
三、二级缓存
Mybatis二级缓存原理:
二级缓存的范围是mapper级别(mapper同一个命名空间),mapper以命名空间为单位创建缓存数据结构,结构是map<key, value>。每次查询前看是否开启了二级缓存,如果开启则从二级缓存的数据结构中取缓存数据,如果二级缓存中没有取到,再从一级缓存中取,如果一级缓存也没有,那就从数据库中查询。
二级缓存配置
需要在Mybatis的配置文件中<settings>标签中配置二级缓存:
<settings>
<setting name="cacheEnabled" value="true"/> <!--Mybatis的二级缓存配置-->
</settings>
Mybatis的二级缓存的范围是mapper级别的,因此我们mapper如果想要使用二级缓存,还需要在对应的映射文件中配置<cache>标签
<mapper namespace="com.snow.xml.SnowOracle">
<cache></cache> <!--Mybatis的二级缓存配置-->
</mapper>
测试:
@Test
public void test(){
SqlSession sqlSession1 = DBUtil.getSqlSession();
List<Map<String, Object>> list1 = sqlSession1.selectList("getEmployeeByName", "周康");
System.out.println("list1=" + list1);
sqlSession1.commit();
sqlSession1.close();
DBUtil.closeSqlsession();
SqlSession sqlSession2 = DBUtil.getSqlSession();
List<Map<String, Object>> list2 = sqlSession2.selectList("getEmployeeByName", "周康");
System.out.println("list2=" + list2);
sqlSession2.commit();
sqlSession2.close();
}
在SqlSession2 创建处打断点,观看此时输出:list1=[{ID=70DD7D10-9FC6-4B79-ADAF-8B408DE1E048, EMPNAME=周康, AGE=35, DMGRP=男, BIRTHDATE=1987-07-31 00:00:00.0, SALARY=17000, ADDRESS=湖南长沙, GRADE=高级架构师}]
此时去修改数据库中周康此人的年龄,改为37提交,代码继续往下执行,会看到SqlSession2 与SqlSession1 是两个不同的SqlSession,观看此时输出:list2=[{ID=70DD7D10-9FC6-4B79-ADAF-8B408DE1E048, EMPNAME=周康, AGE=35, DMGRP=男, BIRTHDATE=1987-07-31 00:00:00.0, SALARY=17000, ADDRESS=湖南长沙, GRADE=高级架构师}]
|