二级缓存是 MyBatis 提供的一种缓存机制,用于减少对数据库的访问次数,提高应用程序的性能。它是基于 SQLSessionFactory 级别的缓存,与一级缓存(SQLSession 级别的缓存)不同,二级缓存在多个 SQLSession 之间共享。以下是二级缓存的一些关键点:
形象解释一下:
二级缓存可以形象地比喻成一个共享的图书馆,用来提高数据查询的效率。让我们通过以下比喻来理解二级缓存的工作原理:
比喻场景
假设我们有一个学校图书馆(SQLSessionFactory),学生(SQLSession)经常需要查阅教科书(数据库数据)。每次学生需要某本书时,他们首先会检查自己手中的副本(一级缓存),如果没有找到,他们就会去图书馆查询(数据库查询)。为了避免每次都从书架上拿书,图书馆管理员决定设置一个公共的书架(二级缓存),上面放置了常用的教科书副本,这样所有学生都可以共享这些副本,从而减少从书架上拿书的频率(减少数据库查询次数)。
工作原理
-
一级缓存(个人书包):
- 每个学生都有一个个人书包(一级缓存),他们可以把最近查看的教科书放在书包里。
- 书包中的书只能被该学生使用,不能与其他学生共享。
- 当学生在书包中找不到所需的书时,他们会去图书馆的公共书架上找书。
-
二级缓存(公共书架):
- 图书馆设有一个公共书架(二级缓存),上面放置了所有学生都可以使用的教科书副本。
- 如果某本书已经在公共书架上了,学生就可以直接从公共书架上拿,而不用去书架上重新找。
- 公共书架上的书可以被所有学生共享。
示例
假设有两个学生 A 和 B,他们分别需要查阅同一本教科书《数据结构》。
- 学生 A 需要查阅《数据结构》,他首先检查自己的书包(一级缓存),发现书包里没有这本书。
- 学生 A 去图书馆的公共书架(二级缓存)查看,发现公共书架上也没有《数据结构》。
- 学生 A 只能从图书馆书架(数据库)上找到《数据结构》并将其放在公共书架上,同时自己也把副本放在书包里。
- 后来,学生 B 也需要查阅《数据结构》,他首先检查自己的书包(一级缓存),发现书包里没有这本书。
- 学生 B 去公共书架(二级缓存)查看,发现上面有《数据结构》,于是直接从公共书架上拿书,而不用再去图书馆书架上找书。
通过这个比喻,我们可以理解二级缓存的主要作用是减少对数据库的直接查询,提高数据访问的效率,类似于学生共享公共书架上的教科书,从而减少每次都从书架上拿书的频率。
工作原理
-
缓存作用域:二级缓存的作用范围是整个 SQLSessionFactory,也就是说,同一个 SQLSessionFactory 下创建的多个 SQLSession 可以共享二级缓存的数据。
-
缓存存储:二级缓存会将查询结果存储在缓存中,当同样的查询再次执行时,会直接从缓存中获取结果,而不是重新查询数据库。
-
缓存的有效性:二级缓存是以 namespace 为单位的,也就是说,每个 mapper 的二级缓存是独立的,不同 mapper 之间的缓存数据不会共享。
配置二级缓存
要使用二级缓存,需要在 MyBatis 的配置文件和相应的 mapper 文件中进行配置:
1.在 MyBatis 配置文件中启用全局缓存:
<configuration>
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
</configuration>
2.在 Mapper XML 文件中配置二级缓存:
<mapper namespace="com.example.mapper.UserMapper">
<!-- 开启二级缓存 -->
<cache/>
<!-- SQL 语句 -->
<select id="selectUserById" resultType="User">
SELECT * FROM user WHERE id = #{id}
</select>
</mapper>
示例代码
以下是一个具体的示例,展示如何配置和使用二级缓存:
1.MyBatis 配置文件(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"/>
</settings>
</configuration>
2.Mapper XML 文件(UserMapper.xml):
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.UserMapper">
<cache/>
<select id="selectUserById" resultType="User">
SELECT * FROM user WHERE id = #{id}
</select>
</mapper>
3.Java 代码:
public class MyBatisExample {
public static void main(String[] args) {
SqlSessionFactory sqlSessionFactory = ...; // 获取 SqlSessionFactory
try (SqlSession session1 = sqlSessionFactory.openSession()) {
UserMapper mapper1 = session1.getMapper(UserMapper.class);
User user1 = mapper1.selectUserById(1);
System.out.println(user1);
}
try (SqlSession session2 = sqlSessionFactory.openSession()) {
UserMapper mapper2 = session2.getMapper(UserMapper.class);
User user2 = mapper2.selectUserById(1);
System.out.println(user2);
}
}
}
在上述代码中,selectUserById
方法第一次执行时会查询数据库,并将结果缓存到二级缓存中。当第二次执行相同的方法时,会直接从缓存中获取结果,而不再查询数据库。这样可以显著减少数据库访问次数,提高系统性能。