最近在使用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的每次查询都会清空缓存后在执行。
分享到:
相关推荐
也就是针对于同一事务,多次执行同一Mapper的相同查询方法,第一查询后,MyBatis会将查询结果放入缓存,在中间不涉及相应Mapper的数据更新(Insert,Update和Delete)操作的情况下,后续的查询将会从缓存中获取,而...
SmartSql() 总览 SmartSql = MyBatis +缓存(内存| Redis)+ R / W拆分+动态存储库+诊断... 简单,高效,高性能,可扩展,监视,逐步开发... 经过数次微服务验证后,SmartSql在生产环境中已经脱离正式开源两年多了。
立即执行一次任务。 5、缓存和Session =========== 注解redis缓存数据,Spring-session和redis实现分布式session同步(建议按功能模块划分系统)。 6、日志 =========== logback打印日志,业务日志和调试日志...
1.注意修改db.properties中的数据库配置信息,...5.success.jsp页面中可以测试Redis是否配置成功,多次点击按钮查询观察select的执行情况 6.压缩包里有三个demo1,分别是mybatis二级缓存版、spring4.0版、spring3.0版。
* 客户端不断轮询缓存,查询到对应的秒杀订单,则秒杀成功 秒杀的一些优化(借鉴了网上的思路): * 增加了秒杀的随机路径,防刷 * 在秒杀开始前需要验证码输入,延缓压力 * 利用redis的缓存,限制每个用户的每...
次调用直接从缓存中获取。 • 使用Spring缓存抽象时我们需要关注以下两点; 1、确定方法需要被缓存 以及他们的缓存策略 2、从缓存中读取之前缓存存储的数据 Cache 缓存接口,定义缓存操作。实现有:RedisCache、...
因此可以部分数据从数据库中抽取出来放到应用端以文本方式存储, 或者使用框架(Mybatis, Hibernate)提供的一级缓存/二级缓存,或者使用redis数据库来缓存数据 。负载均衡是应用中使用非常普遍的一种优化方法,它的...
4、最巧妙的缓存应用,将多表关联查询尽量变成单表 5、跨数据库 6、提供行列转换(数据旋转),避免写复杂的sql或存储过程,用算法来化解对sql的高要求,同时实现数据库无关(不管是mysql还是sqlserver) 7、提供分组...
快速搭建专属电商系统,内置多租户saas等功能,方便迅速展开业务,安全便捷,框架成熟稳定便于扩展,支持二次开发定制。 环境必备 Jdk8+ Mysql5.7+ Maven Lombok(重要) 软件架构 核心框架:Spring Boot 2.4.0 安全...
充分利用缓存:秒杀商品是一个典型的读多写少的应用场景,充分利用缓存将大大提高并发量 实现技术点 1. 两次MD5加密 将用户输入的密码和固定Salt通过MD5加密生成第一次加密后的密码,再讲该密码和随机生成
然后,您必须应用缓存机制,以避免多次数据库调用和更快的响应。一个免费的开源内存中缓存系统,可通过减少数据库负载来加速应用程序。用Spring进行Memcached 在这个项目中,您将发现spring REST应用程序中...
面试题包括以下十九部分:Java 基础、容器、多线程、反射、对象拷贝、Java Web 模块、异常、网络、设计模式、Spring/Spring MVC、Spring Boot/Spring Cloud、Hibernate、Mybatis、RabbitMQ、Kafka、Zookeeper、MySql...
Spring Boot、MyBatis、Vue ,内置模块如:部门管理、角色用户、菜单及按钮授权、数据权限、系统参数、日志管理、代码生成等。在线定时任务配置;支持集群,支持多数据源,支持分布式事务 完全响应式布局(支持电脑...
CarpApi开源API接口管理系统,新版历经近100次提交修改,将hibernate替换为mybatis、调整底层结构,项目更加清晰、支持自定义首页、使用google缓存方案替换原有缓存、全新的首页、文章分类调整、支持word&pdf;...
使用Mybatis拦截器实现对所有SQL的拦截,修改默认的Schema,从而实现多租户数据隔离的目的。 并且支持可插拔。 9、二级缓存 采用J2Cache操作缓存,第一级缓存使用内存(Caffeine),第二级缓存使用 Redis。 由于大量的...
CarpApi开源API接口管理系统,新版历经近100次提交修改,将hibernate替换为mybatis、调整底层结构,项目更加清晰、支持自定义首页、使用google缓存方案替换原有缓存、全新的首页、文章分类调整、支持word&pdf;...
多线程创建有几种方式?GC是什么? 为什么要有GC?thorw与thows的区别? Log4j常用的四个日志级别是哪四个?优先级顺序是怎样的?拦截器和过滤器有什么区别?程序中是先执行拦截器还是过滤器?请描述Mybatis结果集中...
品达通用权限系统基于SpringCloud(Hoxton.SR1) +SpringBoot(2.2.2.RELEASE) 的微服务框架,具备通用的用户管理、资源权限管理、网关统一鉴权、XSS防跨站攻击等多个模块,支持多业务系统并行开发,支持多服务并行开发...
同时,我们也注重系统的性能和安全性,通过优化数据库查询、使用缓存技术等手段提升系统响应速度,并通过加密传输、权限验证等方式保障用户数据的安全。 在实现方面,我们充分利用了SSM框架的优势,通过Spring实现...
RuoYi是一个后台管理系统,基于经典技术组合(Spring Boot、Apache Shiro、MyBatis、Thymeleaf)主要目的让开发者注重专注业务,降低技术难度,从而节省人力成本,缩短项目周期,提高软件安全质量。 本地版本为截止...