MyBatis之缓存

2023-12-29 16:17:00

系列文章目录

提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
MyBatis之缓存


提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

提示:这里可以添加本文要记录的大概内容:

在当今的 Web 应用程序中,性能是至关重要的。缓存是提高应用程序性能的一种常用技术,它可以减少数据库查询的次数,从而提高应用程序的响应时间。MyBatis 是一个流行的 Java ORM(对象关系映射)框架,它提供了强大的缓存功能,可以帮助开发者提高应用程序的性能。
在本博客中,我们将介绍 MyBatis 缓存的基本概念和工作原理,以及如何在 MyBatis 中配置和使用缓存。我们还将介绍一些常见的缓存策略和缓存过期机制,以帮助开发者更好地管理缓存。此外,我们还将提供一些实际的案例,以帮助开发者更好地理解如何在应用程序中使用 MyBatis 缓存。
通过阅读本博客,开发者将了解 MyBatis 缓存的基本概念和工作原理,掌握如何在 MyBatis 中配置和使用缓存,以及如何管理缓存以提高应用程序的性能。无论是新手还是有经验的开发者,都可以从本博客中获得有价值的信息和技巧,以帮助他们更好地开发高性能的 Web 应用程序。


提示:以下是本篇文章正文内容,下面案例可供参考

一、 MyBatis 缓存的基本概念

在 Web 应用程序中,数据库操作通常是性能瓶颈之一。为了提高数据库操作的性能,缓存是一种常用的技术。MyBatis 是一个流行的 Java ORM(对象关系映射)框架,它提供了强大的缓存功能。
MyBatis 缓存是在内存中存储查询结果的一种机制,它可以避免频繁地查询数据库。当相同的查询再次执行时,MyBatis 会从缓存中获取结果,而不是再次执行数据库查询。这样可以大大提高查询的性能。MyBatis 缓存有两种类型:一级缓存和二级缓存。
一级缓存是在 Session 层面上的缓存,它只适用于当前会话。当相同的查询在同一个会话中再次执行时,MyBatis 会从一级缓存中获取结果。
二级缓存是在整个应用程序层面上的缓存,它可以跨会话共享。当相同的查询在不同的会话中再次执行时,MyBatis 会从二级缓存中获取结果。

二、MyBatis 缓存工作原理

MyBatis 缓存的工作原理如下:
1.一级缓存:

  • 缓存级别:sqlsession 级别。
  • 缓存内容:查询 SQL 语句的结果。
  • 缓存方式:使用 Map 数据结构,key 的格式为 offset+sql,limit+sql,value 存储查询结果。
  • 缓存规则:在同一个 sqlsession 中进行相同的 SQL 语句查询时,第二次以后的查询不会从数据库查询,而是直接从缓存中获取。一级缓存最多缓存 1024 条。
  • 缓存更新:如果两次查询中间出现了 Commit 操作(修改、添加、删除),本 sqlsession 中的一级缓存区域会全部清空,下次再去缓存中查询不到,需要从数据库查询并写入缓存。
    2.二级缓存:
  • 缓存级别:mapper 级别,不同的 sqlsession 可以共享。
  • 缓存内容:查询 SQL 语句的结果。
  • 缓存方式:使用 Map 数据结构,key 的格式为 mapperld+offset+sql,offset+sql,limit+sql+所有的入参。
  • 缓存规则:对于同一个命名空间下的 SQL 语句,MyBatis 会将查询结果存储在二级缓存中。不同的 sqlsession 可以共享同一个命名空间下的二级缓存。
  • 缓存更新:二级缓存是通过 executor 实现的,executor 是 executor 的代理对象。所有的查询操作在 executor 中都会先匹配缓存中是否存在,不存在则查询数据库。

三、MyBatis一级缓存

MyBatis的一级缓存在默认情况下是开启的,是SqlSession级别的缓存,每个SqlSession都有自己单独的一级缓存,多个SqlSession之间的一级缓存是相互隔离的,互不影响。一级缓存的工作原理为:在同一个SqlSession中多次执行相同的查询时,每次执行都会先在一级缓存中查找,如果缓存中有就直接返回;如果一级缓存中没有相关数据,MyBatis就会去db中进行查找,然后将查找到的数据放入一级缓存中,第二次执行相同的查询时,会发现缓存中已经存在,会直接返回。一级缓存的存储介质是内存,是用一个HashMap来存储数据的,所以访问速度是非常快的。SqlSession对象中包含一个Executor对象,Executor对象中包含一个PerpetualCache对象,在该对象存放一级缓存数据。

清楚一级缓存

  • SqlSession调用close():操作后SqlSession对象不可用,该对象的缓存数据也不可用。
  • SqlSession调用clearCache()/commit():操作会清空一级缓存数据。
  • SqlSession调用增删改方法:操作会清空一级缓存数据,因为增删改后数据库发生改变,缓存数据将不准确。
  • 提交或回滚当前数据库事务,这也会自动清除一级缓存。

四、MyBatis二级缓存

  • MyBatis 二级缓存也被称为全局缓存,它将数据存储在 SqlSessionFactory 中。只要是由同一个工厂对象创建的 SqlSession,在进行查询时都可以共享这些数据。通常在一个项目中只有一个 SqlSessionFactory 对象,因此二级缓存中的数据是在整个项目中共享的。
  • 在 MyBatis 中,一级缓存存储的是对象本身,而二级缓存存储的是对象的数据。因此,对于要存储在二级缓存中的 POJO(Plain Old Java Object),必须实现 Serializable 接口,以确保它们可以被序列化。
  • MyBatis二级缓存默认不开启,手动开启后数据先存放在一级缓存中,只有一级缓存数据清空后,数据才会存到二级缓存中。SqlSession调用clearCache()无法将数据存到二级缓存中。

开启二级缓存

1.POJO类实现Serializable接口
2.在MyBatis配置文件添加如下设置:

<settings>
  <setting name="cacheEnabled" value="true"/>
</settings>

3.在映射文件添加标签,该映射文件下的所有方法都支持二级缓存。如果查询到的集合中对象过多,二级缓存只能缓存1024个对象引用。可以通过标签的size属性修改该数量。

<cache size="2048"/>

以下是一个简单的示例,用于测试 MyBatis 二级缓存的功能:

import org.apache.ibatis.io.VFS;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.Reader;
import java.util.ArrayList;
import java.util.List;

public class MyBatisCacheTest {

    public static void main(String[] args) {
        // 创建 SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = createSqlSessionFactory();

        try (SqlSession sqlSession1 = sqlSessionFactory.openSession();
             SqlSession sqlSession2 = sqlSessionFactory.openSession()) {

            // 执行查询,将结果存储在二级缓存中
            List<Pojo> result1 = sqlSession1.selectList("cacheableSelect", 1);
            System.out.println("查询结果 1:" + result1);

            // 再次执行查询,应该从二级缓存中获取结果
            List<Pojo> result2 = sqlSession2.selectList("cacheableSelect", 1);
            System.out.println("查询结果 2:" + result2);

            // 验证结果是否一致
            assert result1.equals(result2);

            // 执行更新操作,清空二级缓存
            sqlSession1.update("cacheableUpdate", 1);

            // 再次执行查询,应该从数据库中获取结果
            List<Pojo> result3 = sqlSession2.selectList("cacheableSelect", 1);
            System.out.println("查询结果 3:" + result3);

        } finally {
            // 关闭 SqlSessionFactory
            sqlSessionFactory.close();
        }
    }

    private static SqlSessionFactory createSqlSessionFactory() {
        // 配置 MyBatis 的 XML 映射文件路径
        String resource = "mybatis-config.xml";

        // 创建 VFS 虚拟文件系统,用于读取配置文件
        VFS vfs = new VFS();
        vfs.addImplClass("org.apache.ibatis.io.VFS");

        // 读取 MyBatis 的配置文件
        Reader reader = vfs.getReader(resource);

        // 创建 SqlSessionFactoryBuilder
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        builder.setXmlReader(reader);

        // 创建 SqlSessionFactory
        return builder.build();
    }

    // 可序列化的 Pojo 类,用于存储测试数据
    static class Pojo implements Serializable {
        private int id;
        private String name;

        public Pojo(int id, String name) {
            this.id = id;
            this.name = name;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            Pojo pojo = (Pojo) o;

            return id == pojo.id;
        }

        @Override
        public int hashCode() {
            return id;
        }
    }
}

在上述示例中,我们首先创建了一个SqlSessionFactory,然后使用两个SqlSession对象执行相同的查询。第一次查询会将结果存储在二级缓存中,第二次查询会从缓存中获取结果。
接着,我们更新了数据库中的数据,并再次使用SqlSession对象执行查询。由于之前的更新操作清空了二级缓存,这次查询会直接从数据库中获取最新的数据。
请确保在实际应用中,你的POJO类需要实现Serializable接口,以便在二级缓存中进行序列化和反序列化。

缓存过期时间配置

在Mybatis中,缓存过期机制是指缓存中的数据在一定时间后自动过期,需要从数据库中重新获取。以下是Mybatis中常见的缓存过期机制:

  • 默认过期时间:缓存中的数据在默认情况下会一直存在,直到手动清空缓存或应用程序停止运行。
  • 二级缓存过期时间配置:在配置文件中设置cache-expiry-seconds属性来指定缓存过期时间,默认过期时间为1小时。
  • 一级缓存过期时间配置:默认情况下,一级缓存没有过期时间。如果需要设置过期时间,可以在sqlSession创建时通过setDefaultTimeout方法进行配置,或者在查询语句中使用flushCache或clearCache来手动刷新或清除缓存。

缓存过期时间的配置可以根据具体的业务需求和数据访问模式来选择合适的时间,以最大程度地提高数据库操作的性能和效率。


总结

提示:这里对文章进行总结:

缓存是将一些临时数据存储到内存中,由于服务器的内存有限,所以缓存只能存储一些数据量小的数据。缓存的速率较快,使用方便。缓存虽然可以提高数据查询效率,但同时也可能会带来缓存同步、缓存失效、缓存雪崩等问题。因此,在使用缓存时需要根据具体的业务需求和数据访问模式来选择合适的缓存策略和过期机制,以最大程度地提高数据库操作的性能和效率。

文章来源:https://blog.csdn.net/liubopro666/article/details/135289296
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。