mybatis一级缓存默认开启
一级缓存只是相对于同一个SqlSession而言。所以在参数和SQL完全一样的情况下,我们使用同一个SqlSession对象调用一个Mapper方法,往往只执行一次SQL。
1.例如:
@Test
public void testUnit() {
System.out.println(employeeMapper.selectById(7369));
System.out.println(employeeMapper.selectById(7369).getDepartment());
System.out.println("------------------------------------------");
System.out.println(employeeMapper.selectById(7369));
System.out.println(employeeMapper.selectById(7369).getDepartment());
}
2.结果:
2020-03-29 19:26:02,228 [main] DEBUG [lz.cn.mapper.EmployeeMapper.selectById] - ==> Preparing: select e.EMPNO, e.ENAME, e.JOB, e.MGR, e.HIREDATE, e.SAL, e.COMM, e.DEPTNO, d.DEPTNO D_DEPTNO, d.DNAME D_DNAME, d.LOC D_LOC from EMPLOYEE E,DEPARTMENT D where E.DEPTNO = D.DEPTNO and E.EMPNO=?
2020-03-29 19:26:02,571 [main] DEBUG [lz.cn.mapper.EmployeeMapper.selectById] - ==> Parameters: 7369(Integer)
2020-03-29 19:26:02,712 [main] DEBUG [lz.cn.mapper.EmployeeMapper.selectById] - <== Total: 1
Employee{empno=7369, ename='FIRST', job='JAVA', mgr=7369, hiredate=Fri Sep 27 18:17:07 CST 2019, sal=4000.0, comm=100.0, deptno=10}
部门{deptno=10, dname='ACCOUNTING', loction='null'}
------------------------------------------
Employee{empno=7369, ename='FIRST', job='JAVA', mgr=7369, hiredate=Fri Sep 27 18:17:07 CST 2019, sal=4000.0, comm=100.0, deptno=10}
部门{deptno=10, dname='ACCOUNTING', loction='null'}
如结果所示,sql语句只输出了一次,同一个sqlSession中只执行了一次查询。
3.一级缓存的生命周期
- 创建一个新的SqlSession对象后,SqlSession对象中会有一个新的Executor对象。Executor对象中持有一个新的PerpetualCache对象;当会话结束时,SqlSession对象及其内部的Executor对象还有PerpetualCache对象也一并释放掉。
- 如果SqlSession调用了close()方法,会释放掉一级缓存PerpetualCache对象,一级缓存将不可用。
- SqlSession调用了clearCache(),会清空PerpetualCache对象中的数据,但是该对象仍可使用
- SqlSession中执行了任何一个update操作(update()、delete()、insert()) ,都会清空PerpetualCache对象的数据,但是该对象可以继续使用
二级缓存开启步骤:
MyBatis的二级缓存是Application级别的缓存,它可以提高对数据库查询的效率,以提高应用的性能。
二级缓存是在SqlSessionFactory层面上的,默认是不开启的,二级缓存的开席需要进行配置,实现二级缓存的时候,MyBatis要求返回的POJO必须是可序列化的。 也就是要求实现Serializable接口。
配置方法:
要求实现Serializable接口。
1.在mybatis的配置文件中添加
<settings>
<!--二级缓存-->
<setting name="cacheEnabled" value="true"/>
</settings>
2.在mapper中添加:
<!--二级缓存开启-->
<cache eviction="LRU"
flushInterval="60000"
size="1024"
readOnly="true"/>
cache 标签有多个属性:
- eviction:缓存回收策略
- LRU - 最近最少回收,移除最长时间不被使用的对象
- FIFO - 先进先出,按照缓存进入的顺序来移除它们
- SOFT - 软引用,移除基于垃圾回收器状态和软引用规则的对象
- WEAK - 弱引用,更积极的移除基于垃圾收集器和弱引用规则的对象
- flushInterval:缓存刷新间隔,缓存多长时间刷新一次,默认不清空,设置一个毫秒值
- readOnly:是否只读;true 只读,MyBatis 认为所有从缓存中获取数据的操作都是只读操作,不会修改MyBatis 为了加快获取数据,直接就会将数据在缓存中的引用交给用户。不安全,速度快。读写(默认):MyBatis 觉得数据可能会被修改
- size:缓存存放多少个元素
3.test测试
SqlSessionFactory sqlSessionFactory = null;
/*第一个sqlSession*/
SqlSession sqlSession = sqlSessionFactory.openSession();
EmployeeMapper employeeMapper1 = sqlSession.getMapper(EmployeeMapper.class);
System.out.println(employeeMapper1.selectById(8133));
sqlSession.close();
/*第二个sqlSession*/
SqlSession sqlSession2 = sqlSessionFactory.openSession();
EmployeeMapper employeeMapper2 = sqlSession2.getMapper(EmployeeMapper.class);
System.out.println(employeeMapper2.selectById(8133));
sqlSession2.close();
/*第三个sqlSession*/
SqlSession sqlSession3 = sqlSessionFactory.openSession();
EmployeeMapper employeeMapper3 = sqlSession3.getMapper(EmployeeMapper.class);
System.out.println(employeeMapper3.selectById(8133));
sqlSession3.close();
此处同一个sqlSessionFactory开启三个sqlSession,查询同一个员工。
4.结果显示:
2020-03-29 18:45:34,558 [main] DEBUG [com.yw.mapper.EmployeeMapper] - Cache Hit Ratio [com.yw.mapper.EmployeeMapper]: 0.0
2020-03-29 18:45:36,167 [main] DEBUG [com.yw.mapper.EmployeeMapper.selectById] - ==> Preparing: select * from EMPLOYEE where EMPNO=?
2020-03-29 18:45:36,355 [main] DEBUG [com.yw.mapper.EmployeeMapper.selectById] - ==> Parameters: 8133(Integer)
2020-03-29 18:45:36,464 [main] DEBUG [com.yw.mapper.EmployeeMapper.selectById] - <== Total: 1
Employee{empno=8133, ename='employee', job='employee', mgr=7369, hiredate=Tue Oct 15 16:07:09 CST 2019, sal=500.0, comm=200.0, deptno=20}
2020-03-29 18:45:36,480 [main] DEBUG [com.yw.mapper.EmployeeMapper] - Cache Hit Ratio [com.yw.mapper.EmployeeMapper]: 0.5
Employee{empno=8133, ename='employee', job='employee', mgr=7369, hiredate=Tue Oct 15 16:07:09 CST 2019, sal=500.0, comm=200.0, deptno=20}
2020-03-29 18:45:36,480 [main] DEBUG [com.yw.mapper.EmployeeMapper] - Cache Hit Ratio [com.yw.mapper.EmployeeMapper]: 0.6666666666666666
Employee{empno=8133, ename='employee', job='employee', mgr=7369, hiredate=Tue Oct 15 16:07:09 CST 2019, sal=500.0, comm=200.0, deptno=20}
2020-03-29 18:45:36,480 [main] DEBUG [com.yw.mapper.EmployeeMapper] - Cache Hit Ratio [com.yw.mapper.EmployeeMapper]: 0.75
Employee{empno=8133, ename='employee', job='employee', mgr=7369, hiredate=Tue Oct 15 16:07:09 CST 2019, sal=500.0, comm=200.0, deptno=20}
控制台结果打印:
第一次没有缓存,命中率0.0,需要查询,有sql语句;
第二次有缓存,命中率0.5,直接从缓存中取得数据,无查询,无sql语句;(共两次命中1次)
第三次有缓存,命中率0.666,直接从缓存中取得数据,无查询,无sql语句;(共三次命中2次)
第四次有缓存,命中率0.75,直接从缓存中取得数据,无查询,无sql语句;(共四次命中3次)
5.效果
- 所有select语句将会被缓存。
- insert、update和delete语句会刷新缓存
- 默认的Least Recently Used(LRU,最近最少使用的)算法来收回