mybatis 二级缓存

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
云数据库 RDS MySQL Serverless,价值2615元额度,1个月
简介: Mybatis读取缓存次序:先从二级缓存中获取数据,如果有直接获取,如果没有进行下一步;从一级缓存中取数据,有直接获取,如果没有进行下一步;到数据库中进行查询,并保存到一级缓存中;当sqlSession关闭的时候,把一级缓存中的数据保存在二级缓存中。

Mybatis读取缓存次序:

  1. 先从二级缓存中获取数据,如果有直接获取,如果没有进行下一步;
  2. 从一级缓存中取数据,有直接获取,如果没有进行下一步;
  3. 到数据库中进行查询,并保存到一级缓存中;
  4. 当sqlSession关闭的时候,把一级缓存中的数据保存在二级缓存中。

二级缓存的使用:

myBatis的二级缓存默认是不开启的。我们需要在mybatis的核心配置文件中配置setting选项 和 在Mapper的配置文件中加入cache标签

启用二缓存分两步:

1、mybatis-config.xml中配置全局的参数       

<!-- 开启二缓存 -->
        <setting name="cacheEnabled" value="true" />

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

  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 属性表示自定义二级缓存对象。 

 
 
 
 
相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
3月前
|
缓存 Java 数据库连接
MyBatis的缓存
MyBatis的缓存
|
4月前
|
存储 缓存 Java
干翻Mybatis源码系列之第八篇:Mybatis二级缓存的创建和存储
干翻Mybatis源码系列之第八篇:Mybatis二级缓存的创建和存储
|
16天前
|
XML 缓存 Java
MyBatis二级缓存解密:深入探究缓存机制与应用场景
MyBatis二级缓存解密:深入探究缓存机制与应用场景
50 2
MyBatis二级缓存解密:深入探究缓存机制与应用场景
|
1月前
|
存储 缓存 Java
什么!?实战项目竟然撞到阿里面试的原题!???关于MyBatis Plus的缓存机制
什么!?实战项目竟然撞到阿里面试的原题!???关于MyBatis Plus的缓存机制
|
1月前
|
缓存 Java 数据库连接
mybatis 数据库缓存的原理
MyBatis 是一个流行的 Java 持久层框架,它封装了 JDBC,使数据库交互变得更简单、直观。MyBatis 支持两级缓存:一级缓存(Local Cache)和二级缓存(Global Cache),通过这两级缓存可以有效地减少数据库的访问次数,提高应用性能。
282 1
|
1月前
|
存储 缓存 Java
【MyBaits】4、延迟加载、MyBatis 的缓存
【MyBaits】4、延迟加载、MyBatis 的缓存
22 0
|
2月前
|
SQL 缓存 Java
mybatis缓存详解
mybatis缓存详解
23 0
|
3月前
|
缓存 Java 数据库连接
mybatis的缓存内容(下)
mybatis的缓存内容
30 0
|
3月前
|
SQL 缓存 Java
mybatis的缓存内容(上)
mybatis的缓存内容
31 0
|
3月前
|
缓存 Java 数据库连接