缓存是一般的ORM 框架都会提供的功能,目的就是提升查询的效率和减少数据库的压力。mybatis同样也提供了缓存机制。
mybatis的缓存分为两级:一级缓存、二级缓存
默认情况下,只有一级缓存开启,一级缓存是SqlSession级别的缓存,缓存的数据只在SqlSession内有效。
*
二级缓存需要手动开启和配置,二级缓存是(namespace)mapper级别的缓存,同一个namespace公用这一个缓存,所以对SqlSession是共享的。
*
为了提高可扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来定义二级缓存。
这个缓存系统默认情况下是开启的,当我们获取到一个SqlSession对象之后,如果调用SqlSession中的同一个方法查询同一条数据,那么第二次查询将不会去数据库中查询,因为第一次查询有缓存,直接调用缓存数据即可,除非缓存超时或者我们明确声明数据要刷新,否则都是直接调用缓存数据。
测试如下:
@Test
public void testGetStudentById() {
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
StudentDao mapper = sqlSession.getMapper(StudentDao.class);
//查询同一条数据时会缓存
Student student = mapper.getStudnetById(38);
Student student1 = mapper.getStudnetById(38);
System.out.println(student);
System.out.println(student1);
sqlSession.commit();
sqlSession.close();
}
效果如下:
可以看到:我这里执行了两次查询,但实际上只执行了一次SQL语句。
注意事项:
1、如果SqlSession执行了DML操作(insert、update、delete),并commit了,那么mybatis就会清空当前SqlSession缓存中的所有缓存数据,这样可以保证缓存中的存的数据永远和数据库中一致,避免出现脏读。
2、我们也可以手动清理缓存
sqlSession.clearCache();
上面的缓存是由系统默认配置的,这个有一定的局限性,就是只能在同一个SqlSession中有效,脱离了同一个SqlSession就没法使用这个缓存了,一级缓存作用域太低了,有的时候我们可能希望能够跨SqlSession进行数据缓存。那么这个时候需要我们进行手动开启二级缓存。
二级缓存是mapper级别的缓存,也就是同一个namespace的mappe.xml,当多个SqlSession使用同一个Mapper操作数据库的时候,得到的数据会缓存在同一个二级缓存区域。
我们做下测试,首先不开启二级缓存,使用不同的SqlSession操作同一个Mapper下面的同一个查询语句:
@Test
public void testGetStudentById() {
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
StudentDao mapper = sqlSession.getMapper(StudentDao.class);
Student student = mapper.getStudnetById(38);
System.out.println(student);
sqlSession.commit();
sqlSession.close();
SqlSession sqlSession1 = SqlSessionUtils.getSqlSession();
StudentDao mapper1 = sqlSession1.getMapper(StudentDao.class);
Student student1 = mapper1.getStudnetById(38);
System.out.println(student1);
sqlSession1.commit();
sqlSession1.close();
}
效果如下:
可以看到,没有使用到缓存。
下面我们开启二级缓存:
1、全局显示开启(默认,不添加也可以):
<!--显示的开启全局缓存-->
<setting name="cacheEnabled" value="true"/>
2、在Mapper.xml中使用缓存,只需要我们在userMapper.xml中配置cache节点即可:
<mapper namespace="com.macay.dao.StudentDao">
<cache/>
select语句都会被缓存,所有的delete、insert和update则都会将缓存刷新,还比如缓存将使用LRU算法进行内存回收等。那么这些东西如果需要配置的话,我们可以按如下方式进行配置:
<cache eviction="LRU" flushInterval="20000" size="1024" readOnly="true"/>
这里的eviction表示缓存策略,除了LRU之外还有先进先出(FIFO)、软引用(SOFT)、弱引用(WEAK)等,flushInterval则表示刷新时间,表示缓存的对象个数,readOnly为true则表示缓存只可以读取不可以修改。
做了如上配置之后还不够,开启二级缓存还要求我们的实体类可以序列化,实现Serializable接口即可,如下:
ublic class Student implements Serializable {
private Integer id;
private String name;
private String email;
private Integer age;
private Boolean partyMember;
private Classess cla;
private List<Integer> hobbies;
private GenderEnum gender;
private Date regDate;
测试一下:
@Test
public void testGetStudentById() {
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
StudentDao mapper = sqlSession.getMapper(StudentDao.class);
Student student = mapper.getStudnetById(38);
System.out.println(student);
sqlSession.commit();
sqlSession.close();
SqlSession sqlSession1 = SqlSessionUtils.getSqlSession();
StudentDao mapper1 = sqlSession1.getMapper(StudentDao.class);
Student student1 = mapper1.getStudnetById(38);
System.out.println(student1);
sqlSession1.commit();
sqlSession1.close();
}
可以看到SQL语句实际上只执行了一次。
具体流程:
1.当一个sqlseesion执行了一次select后,在关闭此session的时候,会将查询结果缓存到二级缓存
2.当另一个sqlsession执行select时,首先会在他自己的一级缓存中找,如果没找到,就回去二级缓存中找,找到了就返回,就不用去数据库了,从而减少了数据库压力提高了性能。
注意事项:
1、如果SqlSession执行了DML操作(insert、update、delete),并commit了,那么mybatis就会清空当前mapper缓存中的所有缓存数据,这样可以保证缓存中的存的数据永远和数据库中一致,避免出现脏读。
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/weixin_44075963/article/details/116462828
内容来源于网络,如有侵权,请联系作者删除!