MyBatis 之五:MyBatis 的缓存机制

本文详细介绍了MyBatis的一级缓存和二级缓存机制,包括它们的开启方式、验证方法,以及查询时的缓存查找顺序。还提到了如何使用EhCache作为第三方缓存组件,并强调了对象序列化的必要性。
摘要由CSDN通过智能技术生成

(关注+点赞是我继续的最大动力,谢谢支持!) 

缓存

MyBatis 提供了缓存机制来提高应用程序性能,特别是对于那些频繁读取但更新不那么频繁的数据。

MyBatis 提供了一级缓存和二级缓存

一级缓存(本地缓存)

一级缓存默认是开启,可以直接使用的。属于 SqlSession级别的缓存。

  • 一级缓存是 SqlSession 级别的缓存,它在默认情况下是自动开启的。
  • 当同一个 SqlSession 执行 SQL 查询时,如果查询条件相同,MyBatis会首先检查一级缓存中是否存在该查询结果。如果存在,则直接从缓存返回数据,不再执行数据库查询操作。
  • 一级缓存生命周期与 SqlSession 绑定,也就是说,一旦 SqlSession 关闭,一级缓存就会被清空。
  • 对于任何 INSERT、UPDATE 或 DELETE 操作,MyBatis 都会清空当前 SqlSession 中的一级缓存,以确保缓存中的数据与数据库保持同步。
一级缓存验证
/**
 * 一级缓存,SqlSession级别的缓存
 *
 * * 1.sqlSession.clearCache();//清空缓存
 * * 2.flushCache="true"  在映射文件中<select>
 * * 3.执行了更新操作:update insert delele
 * * 4.sqlSession.commit();  rollback(); //引起清空一级缓存的
 * * 5.不同的映射或SQL 都不能相互缓存
 */
public class TestLeveOne {

    public static void main(String[] args) {
        SqlSession session = MyBatisUtil.getSqlSession();
        IDeptDao deptDao = session.getMapper(IDeptDao.class);
        Dept dept1 = deptDao.get(10); //发起SQL
        System.out.println("---------------------------------------");
        //1.清空缓存
//        session.clearCache();

        //2.回滚
//        session.rollback();

        //3. 更新操作:插入 修改 删除
        Dept dept = new Dept();
        dept.setDname("营销部");
        dept.setDeptno(70);

        deptDao.save(dept); //导致清空缓存

        dept1 = deptDao.get(10); //发起SQL

    }


    /**
     * 证明:
     * 1. 一级缓存默认开启的 存在的
     * 2. 一级缓存是 SqlSession级别的缓存(缓存对象在 SqlSession中创建)。
     *
     */
    public static void test1() {
        SqlSession session = MyBatisUtil.getSqlSession();
        IDeptDao deptDao = session.getMapper(IDeptDao.class);

        Dept dept1 = deptDao.get(10); //发起SQL
        System.out.println("*******************上面语句发起SQL,下面语句因缓存中已经存在此对象,所以不再发起SQL**************************");
        Dept dept2 = deptDao.get(10); //未发起SQL
        System.out.println(dept2.hashCode()+"==通过hashcode() 来查看是否为同一个对象=="+dept1.hashCode());
        //关闭session
        MyBatisUtil.close(session);

        //重新打开一个新的 session 并重新获取新的 dao 对象
        session = MyBatisUtil.getSqlSession();
        deptDao = session.getMapper(IDeptDao.class);
        Dept dept3 = deptDao.get(10); //发起SQL
    }
}
一级缓存失效情况
  • sqlSession.clearCache();//清空缓存
  • flushCache="true" 在映射文件标记中
  • 执行了更新操作:update insert delele
  • sqlSession.commit(); rollback(); //引起清空一级缓存的
  • 不同的映射或SQL 都不能相互缓存

二级缓存

  • 二级缓存是跨 SqlSession 的,它的作用范围更广,可以被多个 SqlSession 共享。
  • 开启二级缓存需要在 MyBatis 的 mapper XML 文件或对应的 Mapper 接口上进行配置,并且可以选择使用自定义的缓存实现或者集成第三方缓存如 EhCache。
  • 当一个 SqlSession 关闭后,其加载到二级缓存中的数据可以在新的 SqlSession 中继续使用,前提是这些数据尚未过期或因数据库更新而失效。
  • 二级缓存同样需要处理并发访问和数据一致性问题,MyBatis 提供了一些策略来管理缓存项的同步和清除。
二级缓存验证

二级缓存开启的,三个关键步骤:

  1. 配置文件中:(现在版本,默认就是true)

    <setting name="cacheEnabled" value="true"/>
  2. 映射文件中,需要配置

    <mapper namespace="com.wdzl.dao.IDeptDao">
        <!--启用缓存-->
        <cache />
    </mapper>
  3. 使用二级缓存时,需要对实体类进行序列化,所以要求实体类要实现接口Serializable

public class TestLevelTwo {
    public static void main(String[] args) {
        test1();
        System.out.println("-----------------------");
        test1();
        test1();
    }
    public static void test1() {
        SqlSession session = MyBatisUtil.getSqlSession();
        IDeptDao deptDao = session.getMapper(IDeptDao.class);
        Dept dept1 = deptDao.get(10); //发起SQL
        MyBatisUtil.close(session);
    }
}

可以通过日志查看到二级缓存命中率:

第三方缓存组件

Mybatis 内部有自己的缓存实现,如何切换第三方缓存组件。

EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认的CacheProvider。

Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存,Java EE和轻量级容器。它具有内存和磁盘存储,缓存加载器,缓存扩展,缓存异常处理程序,一个gzip缓存servlet过滤器,支持REST和SOAP api等特点

实现步骤:

二级缓存第三方组件:ehcache

配置文件中配置

因为默认true,

当然,如果这里配置为 false ,二级缓存还是会失效的

可以通过下面验证,默认为 true

System.out.println("二级缓存是否被启用: " + sessionFactory.getConfiguration().isCacheEnabled());

注意:不需要被缓存对象实现序列化接口

  • a. 配置依赖,下载jar

    <dependency>
        <groupId>org.mybatis.caches</groupId>
        <artifactId>mybatis-ehcache</artifactId>
        <version>1.2.1</version>
    </dependency>
  • b. 在映射文件中

    <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
  • c. 注意:被缓存的对象类,是不需要实现序列化接口的

  • d. 也可以选择自定义配置:在classpath目录下新建ehcache.xml文件

查询执行顺序

MyBatis 在查询数据时的缓存查找顺序是:

首先:当 SqlSession 执行数据库查询操作时,实际上是从一级缓存(本地缓存)开始查找。

  • 如果在当前 SqlSession 中之前已经执行过相同的 SQL 查询,并且结果仍然有效,则直接从一级缓存返回数据,不再去查询二级缓存或数据库。

然后:如果一级缓存未命中,接下来的行为取决于是否配置并启用了二级缓存(全局缓存)

  • 若二级缓存已启用且包含匹配的数据,则会从二级缓存中获取数据,并将该数据放入到当前 SqlSession 的一级缓存中,以便后续请求可以快速使用一级缓存。
  • 若二级缓存未命中或者未启用,则 MyBatis 会直接查询数据库以获取数据,并将查询结果放入一级缓存中。

所以,在 MyBatis 中进行查询时,正确的缓存查找顺序是一级缓存 -> 二级缓存 -> 数据库

  • 27
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zp8126

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值