1.MyBatis 缓存
MyBatis 包含一个非常强大的查询缓存特性, 它可以非常方便地配置和定制. 缓存可以极大的提升查询效率.
1). 一级缓存
- public Employee getEmpById(Integer id);
- <select id="getEmpById" resultType="com.atguigu.mybatis.bean.Employee" databaseId="mysql">
- select * from tbl_employee where id = #{id}
- </select>
- @Test
- public void testFirstLevelCache() throws IOException {
- SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
- SqlSession openSession = sqlSessionFactory.openSession();
- try {
- EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
- Employee emp01 = mapper.getEmpById(10);
- System.out.println(emp01);
- //
- Employee emp02 = mapper.getEmpById(1-0);
- System.out.println(emp02);
- System.out.println(emp01==emp02);
- }finally {
- openSession.close();
- }
- }
2). 一级缓存失效情况
(1).sqlSession 不同
(2).sqlSession 相同, 查询条件不同(当前一级缓存中还没有这个数据)
(3).sqlSession 相同, 两次查询之间执行了增删改操作(这次增删改可能对当前数据有影响)
(4).sqlSession 相同, 手动清除了一级缓存
- public Employee getEmpById(Integer id);
- <select id="getEmpById" resultType="com.atguigu.mybatis.bean.Employee" databaseId="mysql">
- select * from tbl_employee where id = #{id}
- </select>
- @Test
- public void testFirstLevelCache() throws IOException {
- SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
- SqlSession openSession = sqlSessionFactory.openSession();
- try {
- EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
- Employee emp01 = mapper.getEmpById(10);
- System.out.println(emp01);
- //1,Sqlsession 不同
- // SqlSession openSession2 = sqlSessionFactory.openSession();
- // EmployeeMapper mapper2 = openSession2.getMapper(EmployeeMapper.class);
- // Employee emp02 = mapper2.getEmpById(10);
- //2,sqlSession 相同, 查询条件不同
- // Employee emp02 = mapper.getEmpById(3);
- // System.out.println(emp02);
- // System.out.println(emp01==emp02);
- //3,sqlSession 相同, 两次查询之间执行了增删改操作
- // mapper.addEmp(new Employee(null, "testCache", "cache@cache.com", "1"));
- // System.out.println("数据添加成功");
- // Employee emp02 = mapper.getEmpById(10);
- // System.out.println(emp02);
- // System.out.println(emp01==emp02);
- //4,sqlSession 相同, 手动清除了一级缓存
- openSession.clearCache();
- Employee emp02 = mapper.getEmpById(10);
- System.out.println(emp02);
- System.out.println(emp01==emp02);
- }finally {
- openSession.close();
- }
- }
3). 二级缓存
二级缓存(second level cache), 全局作用域缓存.
二级缓存默认不开启, 需要手动配置.
MyBatis 提供二级缓存的接口以及实现, 缓存实现要求 POJO 实现 Serializable 接口.
二级缓存在 SqlSession 关闭或提交之后才会生效.
(1). 二级缓存使用
二级缓存使用:
1. 开启全局二级缓存配置:<setting name="cacheEnabled" value="true"/>
2. 去需要使用二级缓存的 xml 中配置使用二级缓存; 添加 < cache></cache>
3.POJO 需要实现序列化接口
- <setting name="cacheEnabled" value="true"/>
- <mapper namespace="com.atguigu.mybatis.dao.EmployeeMapper">
- <!-- cache: 使用二级缓存的 namespace -->
- <!-- eviction: 缓存的清除策略; LRU|FIFO|SOFT|WEAK -->
- <!-- LRU - 最近最少使用的: 移除最长时间不被使用的对象. -->
- <!-- FIFO - 先进先出: 按对象进入缓存的顺序来移除它们. -->
- <!-- SOFT - 软引用: 基于垃圾回收器状态和软引用规则移除对象. -->
- <!-- WEAK - 弱引用: 更积极地基于垃圾收集器状态和弱引用规则移除对象. -->
- <!-- flushInterval(刷新间隔): 缓存多长时间清空一次, 默认不清空, 可以设置一个毫秒值启用刷新间隔 -->
- <!-- readOnly(只读): 属性可以被设置为 true 或 false -->
- <!-- true: 只读; mybatis 认为所有从缓存中获取数据的操作都是只读操作, 不会修改数据; -->
- <!-- 只读的缓存会给所有调用者返回缓存对象的相同实例. 因此这些对象不能被修改. 提供了可观的性能提升 -->
- <!-- false: 非只读; mybatis 觉得获取的数据可能会被修改; -->
- <!-- 可读写的缓存会 (通过序列化) 返回缓存对象的拷贝. 速度上会慢一些, 但是更安全, 因此默认值是 false -->
- <!-- size(引用数目): 属性可以被设置为任意正整数, 要注意欲缓存对象的大小和运行环境中可用的内存资源. 默认值是 1024 -->
- <!-- type: 属性指定的类必须实现 org.apache.ibatis.cache.Cache 接口. 且提供一个接受 String 参数作为 id 的构造器 -->
- <!-- 指定自定义缓存的全类名, 实现 Cache 接口即可 -->
- <!-- <cache eviction="FIFO" flushInterval="60000" readOnly="false" size="1024"></cache> -->
- <cache></cache>
- </mapper>
- @Test
- public void testSecondLevelCache() throws IOException {
- SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
- SqlSession openSession = sqlSessionFactory.openSession();
- SqlSession openSession2 = sqlSessionFactory.openSession();
- try {
- //1,
- EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
- EmployeeMapper mapper2 = openSession2.getMapper(EmployeeMapper.class);
- Employee emp01 = mapper.getEmpById(1);
- System.out.println(emp01);
- openSession.close();
- // 第二次查询是从二级缓存中拿到的数据, 并没有发送新的 sql
- //mapper2.addEmp(new Employee(null, "aaa", "nnn", "0"));
- Employee emp02 = mapper2.getEmpById(1);
- System.out.println(emp02);
- openSession2.close();
- }finally {
- }
- }
(2). 二级缓存工作原理
二级缓存工作原理:
1. 一个会话, 查询一条数, 这个数据就会被放在当前会话的一级缓存中;
2. 如果会话关闭; 一级缓存中的数据会被保存到二级缓存中; 新的会话查询信息, 就可以参照二级缓存中的内容;
3. 不同 namespace 查出的数据会放在自己对应的缓存中(map):sqlSession===EmployeeMapper==>Employee|DepartmentMapper===>Department
4. 二级缓存工作效果: 查出的数据都会被默认先放在一级缓存中. 只有会话提交或者关闭以后, 一级缓存中的数据才会转移到二级缓存中;
(3). 二级缓存属性设置
1.cacheEnabled="true|false": false 关闭缓存(二级缓存关闭)(一级缓存一直可用的)
2. 每个 select 标签都有 useCache="true|false": false 不使用缓存(一级缓存依然使用, 二级缓存不使用)
3.* 每个增删改标签的: flushCache="true|false":(一级二级都会清除)增删改执行完成后就会清楚缓存;
测试: flushCache="true": 一级缓存会被清空; 二级也会被清空; 每次查询之后都会清空缓存, 缓存是没有被使用的;
4.sqlSession.clearCache(); 只是清除当前 session 的一级缓存
5.localCacheScope: 本地缓存作用域; 一级缓存 SESSION; 当前会话的所有数据保存在会话缓存中; STATEMENT: 可以禁用一级缓存;
/** * MyBatis 系统中默认定义了两级缓存: 一级缓存和二级缓存 * 一级缓存 (本地缓存):sqlSession 级别的缓存; 一级缓存是一直开启的; SqlSession 级别的一个 Map * 与数据库同一次会话期间查询到的数据会放在本地缓存中; * 以后如果需要获取相同的数据, 直接从缓存中拿, 没必要再去查询数据库; * 一级缓存失效情况: 没有使用到一级缓存的情况, 效果就是两次查询都需要向数据库发出查询 * 1、sqlSession 不同 * 2、sqlSession 相同, 查询条件不同 (当前一级缓存中还没有这个数据) * 3、sqlSession 相同, 两次查询之间执行了增删改操作 (这次增删改可能对当前数据有影响) * 4、sqlSession 相同, 手动清除了一级缓存 * * 二级缓存 (全局缓存): 基于 namespace 级别的缓存; 一个 namespace 对应一个二级缓存; * 二级缓存工作原理: * 1、一个会话, 查询一条数, 这个数据就会被放在当前会话的一级缓存中; * 2、如果会话关闭; 一级缓存中的数据会被保存到二级缓存中; 新的会话查询信息, 就可以参照二级缓存中的内容; * 3、不同 namespace 查出的数据会放在自己对应的缓存中 (map):sqlSession===EmployeeMapper==>Employee|DepartmentMapper===>Department * 二级缓存工作效果: 查出的数据都会被默认先放在一级缓存中. 只有会话提交或者关闭以后, 一级缓存中的数据才会转移到二级缓存中; * 二级缓存使用: * 1、开启全局二级缓存配置:<setting name="cacheEnabled" value="true"/> * 2、去需要使用二级缓存的 xml 中配置使用二级缓存; 添加 & lt;cache></cache> * 3、POJO 需要实现序列化接口 * * 缓存有关属性 / 设置: * 1、cacheEnabled="true|false": false 关闭缓存(二级缓存关闭)(一级缓存一直可用的) * 2、每个 select 标签都有 useCache="true|false": false 不使用缓存 (一级缓存依然使用,二级缓存不使用) * 3、* 每个增删改标签的:flushCache="true|false":(一级二级都会清除) 增删改执行完成后就会清楚缓存; * 测试: flushCache="true": 一级缓存会被清空; 二级也会被清空; 每次查询之后都会清空缓存, 缓存是没有被使用的; * 4、sqlSession.clearCache(); 只是清除当前 session 的一级缓存 * 5、localCacheScope: 本地缓存作用域; 一级缓存 SESSION; 当前会话的所有数据保存在会话缓存中; STATEMENT: 可以禁用一级缓存; * @throws IOException */ |
2. 第三方缓存整合
EhCache 是一个纯 Java 的进程内缓存框架, 具有快速, 精干等特点, 是 Hibernate 中默认的 CacheProvider.
MyBatis 定义了 Cache 接口方便我们进行自定义扩展.
参考文档:
http://mybatis.org/ehcache-cache/index.html
来源: https://www.cnblogs.com/CSAH/p/13152304.html