Mybatis读取缓存次序:
- 先从二级缓存中获取数据,如果有直接获取,如果没有进行下一步;
- 从一级缓存中取数据,有直接获取,如果没有进行下一步;
- 到数据库中进行查询,并保存到一级缓存中;
- 当sqlSession关闭的时候,把一级缓存中的数据保存在二级缓存中。
二级缓存的使用:
myBatis的二级缓存默认是不开启的。我们需要在mybatis的核心配置文件中配置setting选项 和 在Mapper的配置文件中加入cache标签
启用二缓存分两步:
1、在mybatis-config.xml中配置全局的参数
2.到Mapper配置文件中书写Cache标签
<cache></cache>
3、实体bean对象要实现java.io.Serializable接口
public class Clazz implements Serializable { private int id; private String name; private List<Student> stus;
没有实现java.io.Serializable接口的错误提示:
@Test public void testSecondCache1() { System.out.println("==================testSecondCache1()======================"); SqlSession session = sqlSessionFactory.openSession(); ClazzMapper clazzMapper = session.getMapper(ClazzMapper.class); Clazz clazz1 = clazzMapper.queryClazzById(1); System.out.println("clazz1 = " + clazz1); session.close(); SqlSession session2 = sqlSessionFactory.openSession(); ClazzMapper clazzMapper2 = session2.getMapper(ClazzMapper.class); Clazz clazz2 = clazzMapper2.queryClazzById(1); System.out.println("clazz2 = " + clazz2); session2.close(); }
开启缓存后运行结果:
==================testSecondCache1()====================== DEBUG [main] - Cache Hit Ratio [com.soyoungboy.onetomany.mapper.ClazzMapper]: 0.0 DEBUG [main] - Opening JDBC Connection DEBUG [main] - Created connection 1791868405. DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@6acdbdf5] DEBUG [main] - ==> Preparing: select c.*,s.id stu_id,s.name stu_name from t_clazz c left join t_student s on c.id = s.clazz_id where c.id = ? DEBUG [main] - ==> Parameters: 1(Integer) DEBUG [main] - <== Total: 3 clazz1 = Clazz [id=1, name=javaEE20170228, stus=[Student [id=1, name=stu0228_张三, clazz=null], Student [id=2, name=stu0228_李四, clazz=null], Student [id=3, name=stu0228_王五, clazz=null]]] DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@6acdbdf5] DEBUG [main] - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@6acdbdf5] DEBUG [main] - Returned connection 1791868405 to pool. DEBUG [main] - Cache Hit Ratio [com.soyoungboy.onetomany.mapper.ClazzMapper]: 0.5 clazz2 = Clazz [id=1, name=javaEE20170228, stus=[Student [id=1, name=stu0228_张三, clazz=null], Student [id=2, name=stu0228_李四, clazz=null], Student [id=3, name=stu0228_王五, clazz=null]]]
常用的属性
userCache默认值是true,表示启用缓存。
如果设置useCache为false就表示不启用二级缓存,不影响一级缓存。
<!-- // 根据 id 查询 key的信息 --> <!-- public Key queryKeyById(int id); --> <select id="queryClazzById" parameterType="int" resultMap="queryClazzById_resultMap" useCache="false"> select c.*,s.id stu_id,s.name stu_name from t_clazz c left join t_student s on c.id = s.clazz_id where c.id = #{id} </select>
运行结果:
结果: ==================testSecondCache1()====================== DEBUG [main] - Opening JDBC Connection DEBUG [main] - Created connection 394714818. DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@1786dec2] DEBUG [main] - ==> Preparing: select c.*,s.id stu_id,s.name stu_name from t_clazz c left join t_student s on c.id = s.clazz_id where c.id = ? DEBUG [main] - ==> Parameters: 1(Integer) DEBUG [main] - <== Total: 3 clazz1 = Clazz [id=1, name=javaEE20170228, stus=[Student [id=1, name=stu0228_张三, clazz=null], Student [id=2, name=stu0228_李四, clazz=null], Student [id=3, name=stu0228_王五, clazz=null]]] DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@1786dec2] DEBUG [main] - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@1786dec2] DEBUG [main] - Returned connection 394714818 to pool. DEBUG [main] - Opening JDBC Connection DEBUG [main] - Checked out connection 394714818 from pool. DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@1786dec2] DEBUG [main] - ==> Preparing: select c.*,s.id stu_id,s.name stu_name from t_clazz c left join t_student s on c.id = s.clazz_id where c.id = ? DEBUG [main] - ==> Parameters: 1(Integer) DEBUG [main] - <== Total: 3 clazz2 = Clazz [id=1, name=javaEE20170228, stus=[Student [id=1, name=stu0228_张三, clazz=null], Student [id=2, name=stu0228_李四, clazz=null], Student [id=3, name=stu0228_王五, clazz=null]]] DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@1786dec2] DEBUG [main] - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@1786dec2] DEBUG [main] - Returned connection 394714818 to pool.
flushCache
flushCache属性默认值是true,在update标签,delete标签,insert标签中有。
表示当执行插入,修改,删除语句的时候,会清空缓存。
如果设置为false,很有肯能会产生脏数据。
xml文件配置:
<!-- // 根据 id 查询 key的信息 --> <!-- public Key queryKeyById(int id); --> <select id="queryClazzById" parameterType="int" resultMap="queryClazzById_resultMap" useCache="true"> select c.*,s.id stu_id,s.name stu_name from t_clazz c left join t_student s on c.id = s.clazz_id where c.id = #{id} </select> <update id="updateClazz" parameterType="com.soyoungboy.onetomany.bean.Clazz" flushCache="false"> update t_clazz set name = #{name} where id = #{id} </update>
测试的java代码:
@Test public void testSecondCacheUpdate() { System.out.println("======================================================"); SqlSession session = sqlSessionFactory.openSession(); ClazzMapper userMapper = session.getMapper(ClazzMapper.class); Clazz user = userMapper.queryClazzById(1); System.out.println(user); session.close(); SqlSession session2 = sqlSessionFactory.openSession(); ClazzMapper userMapper2 = session2.getMapper(ClazzMapper.class); userMapper2.updateClazz(new Clazz(1, "更新了")); session2.commit(); session2.close(); SqlSession session1 = sqlSessionFactory.openSession(); ClazzMapper userMapper1 = session1.getMapper(ClazzMapper.class); user = userMapper1.queryClazzById(1); System.out.println(user); session1.close(); System.out.println("======================================================"); }
现在看看是否产生脏数据:
====================================================== DEBUG [main] - Cache Hit Ratio [com.soyoungboy.onetomany.mapper.ClazzMapper]: 0.0 DEBUG [main] - Opening JDBC Connection DEBUG [main] - Created connection 1791868405. DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@6acdbdf5] DEBUG [main] - ==> Preparing: select c.*,s.id stu_id,s.name stu_name from t_clazz c left join t_student s on c.id = s.clazz_id where c.id = ? DEBUG [main] - ==> Parameters: 1(Integer) DEBUG [main] - <== Total: 3 Clazz [id=1, name=javaEE20170228, stus=[Student [id=1, name=stu0228_张三, clazz=null], Student [id=2, name=stu0228_李四, clazz=null], Student [id=3, name=stu0228_王五, clazz=null]]] DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@6acdbdf5] DEBUG [main] - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@6acdbdf5] DEBUG [main] - Returned connection 1791868405 to pool. DEBUG [main] - Opening JDBC Connection DEBUG [main] - Checked out connection 1791868405 from pool. DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@6acdbdf5] DEBUG [main] - ==> Preparing: update t_clazz set name = ? where id = ? DEBUG [main] - ==> Parameters: 更新了(String), 1(Integer) DEBUG [main] - <== Updates: 1 DEBUG [main] - Committing JDBC Connection [com.mysql.jdbc.JDBC4Connection@6acdbdf5] DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@6acdbdf5] DEBUG [main] - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@6acdbdf5] DEBUG [main] - Returned connection 1791868405 to pool. DEBUG [main] - Cache Hit Ratio [com.soyoungboy.onetomany.mapper.ClazzMapper]: 0.5 Clazz [id=1, name=javaEE20170228, stus=[Student [id=1, name=stu0228_张三, clazz=null], Student [id=2, name=stu0228_李四, clazz=null], Student [id=3, name=stu0228_王五, clazz=null]]] 如上所示,当usecache为true ,flushcache为false,不清空的时候就会出现脏数据
中间更新了数据为"更新了",但是接下来数据并没有读取更新后的数据,而是读取缓存中原有的数据,即脏数据。
<cache></cache>标签的介绍和说明undefined
默认的<cache/>标签的作用:
1、映射语句文件中的所有 select 语句将会被缓存。
2、射语句文件中的所有 insert,update 和 delete 语句会刷新缓存。
3、缓存会使用 Least Recently Used(LRU,最近最少使用的)算法来收回。
4、根据时间表(比如 no Flush Interval,没有刷新间隔), 缓存不会以任何时间顺序 来刷新。
5、缓存会存储列表集合或对象(无论查询方法返回什么)的 1024 个引用。
6、缓存会被视为是 read/write(可读/可写)的缓存,意味着对象检索不是共享的,而 且可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。
cache标签示例解析:
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
eviction 属性表示缓存策略。
- LRU – 最近最少使用的:移除最长时间不被使用的对象。
- FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
- SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
- WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
默认的是 LRU。
flushInterval 属性表示间隔多长时间刷新一下缓冲区,清理一下溢出的数据。以毫秒为单位。
size 属性表示缓存中可以保存多少个对象。默认是1024。
readOnly 属性表示是否只读。如果设置为true。表示缓存中只有一个对象。如果设置为false(默认)每次取出来都会反序列化拷贝一份。
type 属性表示自定义二级缓存对象。