一、缓存的意义
-
将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)去查询,从缓存中进行查询,从而提高查询效率,解决了高并发系统的性能问题。
二、mybatis持久层缓存
- mybatis一级缓存是一个Sqlsession级别,SqlSession只能访问自己的一级缓存数据,二级缓存是跨SqlSession的,是mapper级别的缓存,对于mapper级别的缓存 不同的SqlSession是可以共享的。
三、一级缓存
3.1 原理
- 流程: 第一次发出sql语句查询id为1的用户时,sql查询的结果写入sqlSession一级缓存中,缓存使用的数据结构是一个map<key,value>
key: hashcode+sql+sql输入参数+sql输出参数 (作为SQL的唯一标识)
value: 用户信息。
同一个sqlSession再次发出相同的sql,就从缓存中取数据,不再查询数据库。如果两次中间出现commit操作(修改、添加、删除),此SqlSession中的一级缓存数据全部清空,下次再去缓存中就会查询不到数据再从数据库查询,从数据库查询到后再写入缓存。
每次查询都先从缓存进行查询。
注意:清空时会清空当前sqlsession缓存区域中的全部内容。
3.2 一级缓存配置
- mybatis默认支持一级缓存不需要配置
- 注意:mybatis和Spring整合后进行mapper代理开发,不支持一级缓存,mybatis和Spring整合,Spring按照mapper的模板去生成mapper代理对象,模板中在最后统一关闭sqlsession。
四、二级缓存
4.1 二级缓存原理
- 二级缓存的范围是mapper级别(mapper同一个命名空间),mapper以命名空间为单位创建缓存数据结构,结构为map<key,value>
每次查询先看是否开启二级缓存,如果开启先从二级缓存中数据结构中取缓存数据。
如果从二级缓存中没有取到,再从一级缓存中进行查找,如果一级缓存也没有,从数据库查询。
4.2 mybatis二级缓存配置
- mybaits的二级缓存是mapper范围级别,除了在SqlMapConfig.xml设置二级缓存的总开关,即:<setting name="cacheEnabled" value="true"/>
,还要在具体的mapper.xml中开启二级缓存,即:
<mapper namespace="com.shyroke.mapper.OrderMapper"> <cache /> </mapper>
4.3 注意
- mybatis二级缓存需要将查询结果映射的pojo实现 java.io.serializable接口,如果不实现则抛出异常:org.apache.ibatis.cache.CacheException: Error serializing object. Cause: java.io.NotSerializableException
- 二级缓存可以将内存中的数据写到硬盘,存在对象的序列和反序列化,所以要实现java.io.serializable接口。如果结果映射的pojo中还关联了别的pojo,那么它和它所关联的pojo也都要实现java.io.serializable接口。
4.4 二级缓存的禁用
- 对于变化频率较高的sql,需要禁用二级缓存: 在statement中设置useCache=false可以禁用当前select语句的二级缓存,即每次查询都会发出sql去查询,默认情况是true,即该sql使用二级缓存。
<select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">
4.5 刷新缓存
- 如果SqlSession操作commit操作,对二级缓存进行刷新(全局清空)
设置与commit相关statement(insert,update,delete等标签)的flushCache属性是否刷新缓存,默认值是true,如果设置了为false,即使后台数据库发生了变化,只要缓存没有过期,也只会读取缓存中数据 就会获取不到最新数据。
4.6 测试
public static void main(String[] args) throws IOException { String resource = "resource/mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession session = sessionFactory.openSession(); SqlSession session2 = sessionFactory.openSession(); OrderMapper orderMapper = session.getMapper(OrderMapper.class); OrderMapper orderMapper2 = session2.getMapper(OrderMapper.class); Customer customer=orderMapper.findCustomerById(1); System.out.println(customer); //关闭session,将信息写入二级缓存中 session.close(); Customer customer2=orderMapper2.findCustomerById(1); System.out.println(customer2); }
- 注意:只有关闭sqlSession的时候,才会把信息写入二级缓存中。
4.7 mybatis自带的cache参数属性(了解)
mybatis的cache参数只适用于mybatis维护缓存。
- flushInterval(刷新间隔)可以被设置为任意的正整数,而且它们代表一个合理的毫秒形式的时间段。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。 size(引用数目)可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的可用内存资源数目。默认值是1024。
readOnly(只读)属性可以被设置为true或false。只读的缓存会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。可读写的缓存会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是false。
如下例子:
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
这个更高级的配置创建了一个 FIFO 缓存,并每隔 60 秒刷新,存数结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此在不同线程中的调用者之间修改它们会导致冲突。可用的收回策略有, 默认的是 LRU:
LRU – 最近最少使用的:移除最长时间不被使用的对象。
FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。