最近在使用mybatis的过程中,发现一个问题。如果在同一个事物中,多次同一个查询sql在mybatis的执行过程中,只会查询一次数据库,后几次所返回的对象是mybatis在在内部做了缓存。
Property property = this.findByPropertyId("123");
property.setPropertyId(null);;
property = this.findByPropertyId("123");
System.out.println(property.getPropertyId());
以上的代码,打印的结果为 null , 但是我们所期望的可能是 123 , 我不知道这是mybatis的一个bug还是故意这样去设计的.mybatis在执行查询语句的时候,会在本地做一份缓存信息.在BaseExecutor类中:
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
List<E> list;
localCache.putObject(key, EXECUTION_PLACEHOLDER);
try {
list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
} finally {
localCache.removeObject(key);
}
localCache.putObject(key, list);
if (ms.getStatementType() == StatementType.CALLABLE) {
localOutputParameterCache.putObject(key, parameter);
}
return list;
}
可以看到在queryFromDatabase方法中,查询数据库返回结果之后,mybatis编制了一个cachekey的对象,作为key,返回结果作为value,放入了缓存当中(这个地方没有使用拷贝的函数,所以只要外部修改了值,内部缓存中的值信息也会被修改)
之后再下次查询的时候,会依据一个判断,是否需要执行缓存信息,同样是在BaseExecutor类中.
@SuppressWarnings("unchecked")
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
if (closed) throw new ExecutorException("Executor was closed.");
if (queryStack == 0 && ms.isFlushCacheRequired()) {
clearLocalCache();
}
List<E> list;
try {
queryStack++;
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
if (list != null) {
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
} finally {
queryStack--;
}
if (queryStack == 0) {
for (DeferredLoad deferredLoad : deferredLoads) {
deferredLoad.load();
}
deferredLoads.clear(); // issue #601
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
clearLocalCache(); // issue #482
}
}
return list;
}
看到mybatis判断了 ms.isFlushCacheRequired() 的返回数据,如果为 true 会执行 clearLocalCache 方法,清空缓存信息。如果缓存中获取不到的话,才会继续去查询数据库。
可以从 list = resultHandler == null ? (List<E>) localCache.getObject(key) : null; 代码中看出。
所以当第一次查询放入缓存之后,在外部修改了任何一个值之后,mybatis内部缓存的值也会被修改,而且下次查询不会查询数据库,直接返回缓存中被修改过的值
ms.isFlushCacheRequired() 这段代码的判断是基于了一个MappedStatement 类中的flushCacheRequired 的属性做判断的。flushCacheRequired 变量可以通过注解的方式和xml的方式来配置
1.注解:注解的方式是通过 @Options 注解中 flushCache 的配置
2.配置文件:xml中每一个select 都可以设置 flushCache 的属性
flushCache 设置成true之后,本sql的每次查询都会清空缓存后在执行。
分享到:
相关推荐
一级缓存是SqlSession级别的,同一个SqlSession内的多次查询会复用已缓存的结果;而二级缓存则是Mapper级别的,可以在多个SqlSession之间共享,跨越了单一事务的限制。 Redis,作为一款高性能的键值存储系统,常被...
一级缓存默认开启且无法关闭,主要用于减少同一个会话内的多次数据库访问。 - **二级缓存**:也称为全局会话缓存,它的作用范围覆盖了整个应用程序,可以在不同的SqlSession之间共享缓存数据。二级缓存需要显式地...
一级缓存是SqlSession级别的,同一个SqlSession内的多次相同查询会复用第一次查询的结果,避免了频繁的数据库交互。一级缓存默认开启,但当SqlSession关闭或提交时,缓存会被清空。因此,合理管理SqlSession的生命...
MyBatis的一级缓存是SqlSession级别的,同一个SqlSession内的多次查询会复用之前的结果,避免了重复执行SQL。然而,当SqlSession关闭或提交时,一级缓存就会被清空。二级缓存则是在Mapper(或Namespace)级别,跨...
二级缓存的工作原理是:当某次查询的结果被缓存后,后续相同查询可以直接从缓存中获取,无需再次执行SQL,从而提高了性能。 集成Redis作为二级缓存的优势在于,Redis是一款高效的内存数据结构存储系统,支持多种...
MyBatis作为一个优秀的持久层框架,提供了缓存机制来提升查询速度,减轻数据库负担。本文将深入探讨MyBatis层的缓存处理,以及如何在数据底层进行优化。 首先,我们要理解MyBatis的缓存分为一级缓存和二级缓存。一...
也就是针对于同一事务,多次执行同一Mapper的相同查询方法,第一查询后,MyBatis会将查询结果放入缓存,在中间不涉及相应Mapper的数据更新(Insert,Update和Delete)操作的情况下,后续的查询将会从缓存中获取,而...
例如,调用`getUserById`方法多次,观察是否每次都从缓存中获取数据,以及在缓存过期后是否重新从数据库加载。 总结,通过SpringBoot、MyBatis和Ehcache的结合,我们可以实现高效的本地缓存机制,提高数据读取速度...
一级缓存在SqlSession级别,同一个SqlSession内的多次相同查询会复用第一次查询的结果,避免重复的数据库访问。而二级缓存则在Mapper级别,多个SqlSession之间可以共享缓存数据。 1. **一级缓存** - 默认启用,...
一级缓存的概念是指在MyBatis的一次会话中,缓存查询结果,以便下次查询时直接从缓存中取出结果,而不需要再次查询数据库。这样可以减少数据库查询的次数,提高系统的性能。 MyBatis的一级缓存有两种级别:SESSION...
MyBatis提供了两级缓存:一级缓存默认存在于SqlSession级别,同一个SqlSession内的多次相同查询会直接从缓存获取结果;二级缓存则可跨SqlSession,它是基于namespace的,需要在配置文件中开启,并在Mapper接口或XML...
一级缓存是SqlSession级别的,同一SqlSession内的多次相同查询会复用之前的查询结果,避免了重复的数据库访问。而二级缓存则是Mapper(或Namespace)级别的,它可以跨SqlSession共享数据,提高了数据读取效率。 一...
本篇将详细讲解如何在Mybatis中实现一对多关联映射的查询操作。 首先,我们要明确一对多关联映射的基本概念。在这个例子中,User表(用户表)和Order_form表(订单表)之间存在1-N的关系,意味着一个用户可以有多个...
1. 当执行一次查询操作时,Mybatis会检查一级缓存中是否存在对应的结果。 2. 若缓存中不存在,则执行SQL,从数据库获取结果,并将结果存入一级缓存。 3. 如果后续有相同查询请求,Mybatis会在一级缓存中查找,发现...
1. **一级缓存(Local Cache)**:一级缓存是 SqlSession 级别的缓存,同一个 SqlSession 内的多次查询,如果查询的是相同的 SQL,MyBatis 会直接从缓存中获取结果,而不会再次执行 SQL。但是,当 SqlSession 关闭或...
MyBatis的二级缓存是指在多个SqlSession之间共享缓存。MyBatis的二级缓存可以解决一级缓存无法处理并发情况的问题。MyBatis的二级缓存的工作流程如下: 1. MyBatis在执行Sql语句时,会首先检查二级缓存中是否存在...
需要注意的是,一级缓存对于不同事务或者不同Session是隔离的,也就是说,同一个SqlSession内的多次查询可以复用缓存,但不同SqlSession之间无法共享。此外,如果在同一个SqlSession内修改了数据并提交事务,那么在...
6. **查询优化**:在实际应用中,我们还需要关注性能问题,如是否需要缓存结果,以及如何避免N+1查询问题。有时,通过一次性获取所有关联数据,然后在内存中进行处理,可以提高查询效率。 在提供的压缩包文件...
通过以上讲解,我们可以看到 MyBatis 在处理“一对多”关联查询时的灵活性和高效性。了解并熟练运用这些高级特性,可以大大提高我们的开发效率和代码质量。在实际项目中,结合缓存策略和事务管理,我们可以构建出...