本文详细介绍了Mybatis二级缓存的工作原理和配置方法,帮助读者了解如何启用和使用二级缓存以提高查询效率。同时,文章还探讨了缓存失效的场景以及如何避免缓存击穿和缓存雪崩的问题,提供了多种优化技巧和解决方案。通过学习Mybatis二级缓存,你将掌握如何合理设置缓存以确保数据的一致性和提高系统的性能。
Mybatis缓存简介 Mybatis缓存的基本概念Mybatis缓存是Mybatis提供的一种数据缓存机制,用于提高数据库访问效率。缓存可以分为一级缓存和二级缓存,一级缓存是SqlSession级别的缓存,而二级缓存是Mapper级别的缓存。
Mybatis缓存的级别划分Mybatis缓存分为两种级别:一级缓存和二级缓存。
一级缓存
一级缓存是SqlSession级别的缓存,每个SqlSession默认有独立的缓存,即默认情况下一个SqlSession内部存在缓存,但这个缓存是独立的,不同的SqlSession拥有不同的缓存。
二级缓存
二级缓存是Mapper级别的缓存,可以被多个SqlSession共享。二级缓存的生命周期是整个应用的生命周期。
Mybatis一级缓存详解 一级缓存的工作原理一级缓存是SqlSession级别的缓存,当从数据库查询数据时,Mybatis会将查询结果先放入SqlSession的缓存中。当再次执行相同的查询时,Mybatis会先检查缓存中是否有查询结果,如果有,则直接从缓存中取出,避免了再次进行数据库查询。
缓存的生命周期
SqlSession级别的缓存在SqlSession关闭时会清空。也就是说,当一个SqlSession执行了commit或者rollback方法后,一级缓存就会被清空。
缓存的缓存机制
一级缓存的缓存机制是基于HashMap实现的。当执行一个查询语句时,查询语句的哈希值作为HashMap的键,查询结果作为值。
一级缓存的刷新
当SqlSession执行了以下操作时,一级缓存会刷新:
- 执行了增删改操作
- 执行了flushCache方法
- 设置了SqlSession的setCacheEnabled(false)
使用一级缓存非常简单,只需要确保SqlSession的缓存未被清空即可。默认情况下,Mybatis的SqlSession缓存是开启的。
示例代码
// 创建SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 第一次查询
List<User> users = sqlSession.selectList("com.example.mapper.UserMapper.selectAllUsers");
System.out.println("第一次查询结果:" + users);
// 第二次查询
List<User> usersAgain = sqlSession.selectList("com.example.mapper.UserMapper.selectAllUsers");
System.out.println("第二次查询结果:" + usersAgain);
// 注意:这里没有执行commit或者rollback操作,所以缓存不会被清空
Mybatis二级缓存介绍
二级缓存的作用
二级缓存的作用是将Mapper级别的缓存共享给多个SqlSession,这样可以避免多个SqlSession重复查询数据库,提高查询效率。
二级缓存的特点
- 二级缓存是跨SqlSession的。
- 二级缓存的生命周期是整个应用的生命周期。
- 二级缓存默认是关闭的,需要手动开启。
启用二级缓存
启用二级缓存需要在Mapper接口对应的XML配置文件中进行配置。在Mapper XML文件中,需要添加<cache>
标签。
<mapper namespace="com.example.mapper.UserMapper">
<cache />
<!-- 其他配置 -->
</mapper>
配置二级缓存
可以配置二级缓存的一些属性,如是否开启懒加载、缓存对象的序列化策略等。
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
eviction
:缓存的回收策略,默认是LRU(Least Recently Used)。flushInterval
:缓存刷新的时间间隔(毫秒)。size
:缓存的最大缓存对象数。readOnly
:缓存是否只读,默认是false,即可读可写。
缓存对象的序列化
缓存对象需要实现序列化接口,以便在缓存中存储和读取。
示例代码
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private int id;
private String name;
private String email;
// getters and setters
}
在Mapper中启用二级缓存
启用二级缓存需要在Mapper接口对应的XML配置文件中添加<cache>
标签。
配置示例
<mapper namespace="com.example.mapper.UserMapper">
<cache />
<select id="selectAllUsers" resultType="com.example.model.User">
SELECT * FROM users
</select>
</mapper>
在SqlSession中使用二级缓存
在SqlSession中使用二级缓存,只需要确保SqlSession对应的Mapper接口启用了二级缓存即可。
示例代码
// 创建SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 第一个SqlSession执行查询
List<User> users = sqlSession.selectList("com.example.mapper.UserMapper.selectAllUsers");
System.out.println("第一次查询结果:" + users);
// 关闭SqlSession
sqlSession.close();
// 创建新的SqlSession
SqlSession sqlSession2 = sqlSessionFactory.openSession();
// 第二个SqlSession执行相同的查询
List<User> usersAgain = sqlSession2.selectList("com.example.mapper.UserMapper.selectAllUsers");
System.out.println("第二次查询结果:" + usersAgain);
// 关闭SqlSession
sqlSession2.close();
Mybatis二级缓存使用案例
缓存失效的场景
缓存失效是指缓存中的数据无法满足需求,需要重新查询数据库的情况。以下是一些缓存失效的常见场景:
- 执行了增删改操作
- 会话关闭或提交事务
- 启用二级缓存时,如果查询条件不匹配缓存中的数据,则会触发缓存失效
示例代码
// 创建SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 第一次查询
List<User> users = sqlSession.selectList("com.example.mapper.UserMapper.selectAllUsers");
System.out.println("第一次查询结果:" + users);
// 执行插入操作
User newUser = new User();
newUser.setId(1);
newUser.setName("John");
newUser.setEmail("[email protected]");
sqlSession.insert("com.example.mapper.UserMapper.insertUser", newUser);
// 执行查询操作,此时缓存应该会失效
List<User> usersAgain = sqlSession.selectList("com.example.mapper.UserMapper.selectAllUsers");
System.out.println("第二次查询结果:" + usersAgain);
// 关闭SqlSession
sqlSession.close();
如何避免缓存击穿和缓存雪崩
缓存击穿
缓存击穿是指在某一时刻,缓存中没有数据,但数据库中正好有数据,此时所有请求都直接访问数据库,导致数据库压力过大。
缓存雪崩
缓存雪崩是指缓存失效的时间集中在一个时间段内,导致大量请求直接访问数据库,数据库瞬间压力过大。
解决方案
- 缓存预热:在系统启动的时候就将热点数据加载到缓存中。
- 缓存降级:当缓存和数据库都不可用时,提供降级方案,如返回默认值或错误提示。
- 缓存过期时间分散:避免多个缓存在同一时间点失效。
- 缓存更新策略:采用异步更新策略,减少缓存更新时对数据库的直接访问。
示例代码
// 创建SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 第一次查询
List<User> users = sqlSession.selectList("com.example.mapper.UserMapper.selectAllUsers");
System.out.println("第一次查询结果:" + users);
// 设置缓存过期时间,避免缓存雪崩
sqlSession.getConfiguration().getCache("com.example.mapper.UserMapper").clear();
// 执行查询操作,此时缓存已经失效
List<User> usersAgain = sqlSession.selectList("com.example.mapper.UserMapper.selectAllUsers");
System.out.println("第二次查询结果:" + usersAgain);
// 关闭SqlSession
sqlSession.close();
Mybatis二级缓存优化技巧
二级缓存失效的原因及解决方法
缓存失效原因
- 缓存中的数据过期。
- 执行了增删改操作。
- 数据库中数据发生变化,但缓存没有更新。
解决方法
- 设置合理的缓存过期时间:通过配置
flushInterval
属性,确保缓存不过期。 - 使用版本号或时间戳:在查询时携带版本号或时间戳,确保缓存中的数据是最新的。
- 启用缓存更新:在更新数据库后,手动更新缓存。
示例代码
// 创建SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 第一次查询
List<User> users = sqlSession.selectList("com.example.mapper.UserMapper.selectAllUsers");
System.out.println("第一次查询结果:" + users);
// 更新数据库中用户信息
User user = new User();
user.setId(1);
user.setName("John Updated");
user.setEmail("[email protected]");
sqlSession.update("com.example.mapper.UserMapper.updateUser", user);
sqlSession.commit();
// 执行查询操作,此时缓存应该会失效
List<User> usersAgain = sqlSession.selectList("com.example.mapper.UserMapper.selectAllUsers");
System.out.println("第二次查询结果:" + usersAgain);
// 关闭SqlSession
sqlSession.close();
其他需要注意的问题
- 缓存一致性:确保缓存和数据库中的数据一致。
- 缓存的内存消耗:合理设置缓存大小,避免内存溢出。
- 缓存的序列化:确保缓存对象实现了序列化接口。
- 缓存的并发访问:确保缓存在多线程环境下的并发访问安全。
示例代码
// 创建SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 第一次查询
List<User> users = sqlSession.selectList("com.example.mapper.UserMapper.selectAllUsers");
System.out.println("第一次查询结果:" + users);
// 更新数据库中用户信息
User user = new User();
user.setId(1);
user.setName("John Updated");
user.setEmail("[email protected]");
sqlSession.update("com.example.mapper.UserMapper.updateUser", user);
sqlSession.commit();
// 执行查询操作,此时缓存应该会失效
List<User> usersAgain = sqlSession.selectList("com.example.mapper.UserMapper.selectAllUsers");
System.out.println("第二次查询结果:" + usersAgain);
// 关闭SqlSession
sqlSession.close();
共同學習,寫下你的評論
評論加載中...
作者其他優質文章