(关注+点赞是我继续的最大动力,谢谢支持!)
缓存
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 提供了一些策略来管理缓存项的同步和清除。
二级缓存验证
二级缓存开启的,三个关键步骤:
配置文件中:(现在版本,默认就是true)
<setting name="cacheEnabled" value="true"/>
映射文件中,需要配置
<mapper namespace="com.wdzl.dao.IDeptDao"> <!--启用缓存--> <cache /> </mapper>
使用二级缓存时,需要对实体类进行序列化,所以要求实体类要实现接口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 中进行查询时,正确的缓存查找顺序是一级缓存 -> 二级缓存 -> 数据库
标签:缓存,一级,SQL,二级缓存,SqlSession,session,之五,MyBatis From: https://blog.csdn.net/zp8126/article/details/136738993