MyBatis的二级缓存
二级缓存全局缓存,基于namespace级别的缓存,一个namespace对应于一个二级缓存。
工作机制
- 一个会话,查询一条数据,这个数据就会被放在当前会话的一级缓存中。
- 如果当前会话关闭,一级缓存数据会被保存到二级缓存中,新的会话查询就会查询二级缓存的数据。
- sqlSession 对应了EdptMapper(namespace)和EmployeeMapper 一个namespace对应一个二级缓存
使用
开启二级缓存全局配置
<!-- mybatis-config.xml --> <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <settings> <!-- 这个配置使全局的映射器启用或禁用缓存 --> <setting name="cacheEnabled" value="true" /> </configuration>
去xxxxmapper.xml中配置使用二级缓存
<!-- mybatis-config.xml --> <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="cn.fulong.mybatis.emp.dao.DeptMapper" > <cache eviction="" flushInterval="" size="" readOnly="" /> <!-- eviction: + LRU – 最近最少使用:移除最长时间不被使用的对象。 + FIFO – 先进先出:按对象进入缓存的顺序来移除它们。 + SOFT – 软引用:基于垃圾回收器状态和软引用规则移除对象。 + WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。默认的清除策略是 LRU。 flushInterval:(刷新间隔)属性可以被设置为任意的正整数,设置的值应该是一个以毫秒为单位的合理时间量。 默认情况是不设置,也就是没有刷新间隔,缓存仅仅会在调用语句时刷新。 size:(引用数目)属性可以被设置为任意正整数,要注意欲缓存对象的大小和运行环境中可用的内存资源。默认值是 1024。 readOnly:(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓存对象的相同实例。 因此这些对象不能被修改。这就提供了可观的性能提升。而可读写的缓存会(通过序列化)返回缓存对象的拷贝。 速度上会慢一些,但是更安全,因此默认值是 false。 --> </mpper>
实体实现序列化接口
public class Dept implements Serializable {
缓存相关的设置
- cacheEnabled=true/false 和二级缓存有关(一级缓存默认开启的)
- 每个select标签都有userCache=“true”
- 每个增删改的标签,flushCache=“true” (一二级缓存都会被清除)
- 查询标签默认flushCache=“flase”,显式设置flushCache=“flase”,缓存不会被使用(一二级缓存都会被清空)
- sqlSession.clearCache()只会清除当前session的一级缓存
- 全局配置文件 setting 标签内的 localCacheScope:本地缓存作用域(一级缓存)SESION(默认)/STATEMENT(禁用一级缓存)
开启二级缓存,不同的sqlSession查询同一个sql
/*** * 二级缓存 * @throws IOException */ @Test public void testCache2() throws IOException { // 读取类路径 config目录下的 mybatis-config.xml 配置文件 获取mybatis 全局配置 数据库连接 等信息 String resource = "config/mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); // 必须使用同一个 SqlSessionFactory 获取sqlsession SqlSessionFactory sessionFactory= new SqlSessionFactoryBuilder().build(inputStream); // 获取一个 SqlSession SqlSession openSession =sessionFactory.openSession(); // 获取一个 SqlSession SqlSession sqlSession = sessionFactory.openSession(); try { // 获取一个映射器 DeptMapper mapper= openSession.getMapper(DeptMapper.class); // 查询ID为3的部门的信息 mapper.selectDeptById(3); // 关闭Session 必须要关闭session 不然还是走的一级缓存 openSession.close(); // 获取一个新的映射器 DeptMapper mapperNew= sqlSession.getMapper(DeptMapper.class); // 再次查询ID为3的部门的信息 mapperNew.selectDeptById(3); } finally { // 关闭Session sqlSession.close(); } }
发送了一次sql,缓存被使用了
Created connection 55331187. Returned connection 55331187 to pool. Cache Hit Ratio [cn.fulong.mybatis.emp.dao.DeptMapper]: 0.0 Opening JDBC Connection Checked out connection 55331187 from pool. Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@34c4973] ==> Preparing: select * from tbl_dept where id = ? ==> Parameters: 3(Integer) <== Columns: id, dept_name <== Row: 3, 吴国 <== Total: 1 Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@34c4973] Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@34c4973] Returned connection 55331187 to pool. Cache Hit Ratio [cn.fulong.mybatis.emp.dao.DeptMapper]: 0.5 Process finished with exit code 0