在MyBatis中,一级缓存和二级缓存有何不同?
参考回答
在 MyBatis 中,一级缓存和二级缓存有以下几方面的主要区别:
- 作用范围不同
- 一级缓存:作用范围是
SqlSession
。每一个SqlSession
都有自己独立的一级缓存。当你在同一个SqlSession
中执行多次相同的查询时,MyBatis 会使用一级缓存来避免重复查询数据库。一级缓存只在SqlSession
生命周期内有效,一旦SqlSession
关闭,缓存就会被清除。 - 二级缓存:作用范围是
SqlSessionFactory
,即跨SqlSession
。多个SqlSession
可以共享二级缓存。当你在不同的SqlSession
中执行相同的查询时,MyBatis 会首先检查二级缓存是否存在该结果,如果存在,则直接从缓存中获取数据,而不必再次查询数据库。
- 一级缓存:作用范围是
- 缓存存储位置不同
- 一级缓存:一级缓存存储在
SqlSession
内部内存中,每次查询时都在SqlSession
内部查找。如果缓存命中,直接返回结果;如果未命中,则执行 SQL 查询并缓存数据。 - 二级缓存:二级缓存存储在
SqlSessionFactory
范围内,可以通过配置将缓存存储在外部存储系统中(如EHCache
、Redis
等),或者在内存中存储。二级缓存可以跨多个SqlSession
共享缓存数据。
- 一级缓存:一级缓存存储在
- 生命周期不同
- 一级缓存:缓存数据的生命周期与
SqlSession
一致。每次打开新的SqlSession
时,一级缓存都会被清空;每次SqlSession
提交或回滚事务时,一级缓存会被刷新。 - 二级缓存:缓存数据的生命周期与
SqlSessionFactory
一致。只要不清除,二级缓存中的数据可以跨多个SqlSession
存活,直到缓存清除或过期。
- 一级缓存:缓存数据的生命周期与
- 配置与启用方式不同
- 一级缓存:一级缓存是 默认启用 的,无法关闭。每次打开
SqlSession
时都会启用一级缓存,开发者不需要手动配置。 - 二级缓存:二级缓存需要在 MyBatis 配置文件和映射器文件中进行显式配置。例如,在
mybatis-config.xml
中启用二级缓存,并在 Mapper 文件中为每个映射器启用二级缓存。
- 一级缓存:一级缓存是 默认启用 的,无法关闭。每次打开
- 性能和粒度不同
- 一级缓存:一级缓存通常用于减少同一
SqlSession
内部重复查询的开销,因此它的缓存粒度较小,适用于单一会话中的查询优化。 - 二级缓存:二级缓存跨
SqlSession
有更大的缓存粒度,适用于多次查询相同数据的场景。二级缓存能够有效减少数据库访问次数,特别是在系统负载较大时,能够显著提升性能。
- 一级缓存:一级缓存通常用于减少同一
详细讲解与拓展
- 一级缓存的工作原理
- 作用范围:每个
SqlSession
内都有自己独立的一级缓存,当执行 SQL 查询时,MyBatis 会首先检查一级缓存中是否已经存有该查询的结果。如果缓存中存在数据,就直接从缓存中返回,而不再查询数据库。 -
生命周期:一级缓存的生命周期与
SqlSession
的生命周期相同。当SqlSession
被关闭时,一级缓存会被清空。当SqlSession
提交或回滚事务时,一级缓存会被刷新。 -
清空时机:如果执行了
commit
或rollback
操作,一级缓存会被刷新。此外,当执行增、删、改操作时,也会使得一级缓存的数据失效。 -
示例:
“`java
SqlSession sqlSession = sqlSessionFactory.openSession();
// 第一次查询,从数据库获取
User user1 = sqlSession.selectOne("com.example.UserMapper.selectUserById", 1);
// 第二次查询,相同的 SQL,结果从一级缓存中获取
User user2 = sqlSession.selectOne("com.example.UserMapper.selectUserById", 1);
sqlSession.close(); // 关闭时一级缓存清空
“`
- 二级缓存的工作原理
-
作用范围:二级缓存跨
SqlSession
存在,所有通过相同SqlSessionFactory
创建的SqlSession
对象可以共享二级缓存。如果在不同的SqlSession
中执行相同的查询操作,MyBatis 会首先检查二级缓存中是否存在该数据。如果有,直接从缓存中返回。 -
生命周期:二级缓存的生命周期与
SqlSessionFactory
绑定,可以跨SqlSession
存活。二级缓存的数据不会随着SqlSession
的关闭而清空,直到应用关闭或缓存被手动清理。 -
清空时机:二级缓存中的数据会在执行
update
、insert
、delete
等修改数据的操作时失效,通常需要通过flush
来手动刷新缓存。二级缓存的失效机制相对较复杂,需要开发者手动管理。 -
示例:
“`xml
<mapper namespace="com.example.UserMapper">
<cache/> <!– 启用二级缓存 –>
<select id="selectUserById" resultType="User">
SELECT * FROM users WHERE id = #{id}
</select>
</mapper>
“`- 在
mybatis-config.xml
中启用全局缓存:
- 在
- 一级缓存和二级缓存的区别
- 作用范围:一级缓存是
SqlSession
范围内的缓存,二级缓存是SqlSessionFactory
范围内的缓存。 - 缓存存储位置:一级缓存存储在内存中,每个
SqlSession
内部独立存储;二级缓存可以使用外部缓存框架(如EHCache
、Redis
)来持久化存储,也可以存在内存中。 - 生命周期:一级缓存随着
SqlSession
的生命周期而存在,SqlSession
关闭时缓存清空;二级缓存的生命周期与SqlSessionFactory
一致,可以跨SqlSession
存活。 - 启用方式:一级缓存是 MyBatis 默认启用的,二级缓存需要在 MyBatis 配置文件中手动启用。
- 缓存的使用场景
- 一级缓存:适用于同一个
SqlSession
内的多次查询。例如,处理单次请求时,多次查询同一数据,可以利用一级缓存来避免重复查询数据库。 -
二级缓存:适用于多个
SqlSession
或全局查询共享的场景。例如,多个用户查询相同的数据,或在多次相同的查询中需要减少数据库访问,二级缓存可以显著提高性能。
总结
一级缓存和二级缓存是 MyBatis 提供的两种缓存机制。一级缓存作用范围较小,只在同一个 SqlSession
内有效,用于减少同一会话内的重复查询;而二级缓存跨多个 SqlSession
,可以在更大的范围内共享数据,显著减少数据库访问。一级缓存默认启用,不需要开发者配置,而二级缓存需要在配置文件中显式启用并进行配置。正确使用缓存可以显著提高查询性能,但需要注意缓存的失效机制,以避免出现过时的数据。