`
cheng.xinwei
  • 浏览: 79361 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

【mybatis】多次查询缓存的问题

阅读更多
    最近在使用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的每次查询都会清空缓存后在执行。
   

  
   
0
0
分享到:
评论

相关推荐

    mybatis+redis实现二级缓存

    一级缓存是SqlSession级别的,同一个SqlSession内的多次查询会复用已缓存的结果;而二级缓存则是Mapper级别的,可以在多个SqlSession之间共享,跨越了单一事务的限制。 Redis,作为一款高性能的键值存储系统,常被...

    mybatis+redis缓存配置

    一级缓存默认开启且无法关闭,主要用于减少同一个会话内的多次数据库访问。 - **二级缓存**:也称为全局会话缓存,它的作用范围覆盖了整个应用程序,可以在不同的SqlSession之间共享缓存数据。二级缓存需要显式地...

    Mybatis系列教程Mybatis缓存共17页.pdf

    一级缓存是SqlSession级别的,同一个SqlSession内的多次相同查询会复用第一次查询的结果,避免了频繁的数据库交互。一级缓存默认开启,但当SqlSession关闭或提交时,缓存会被清空。因此,合理管理SqlSession的生命...

    mybatis二级缓存学习

    MyBatis的一级缓存是SqlSession级别的,同一个SqlSession内的多次查询会复用之前的结果,避免了重复执行SQL。然而,当SqlSession关闭或提交时,一级缓存就会被清空。二级缓存则是在Mapper(或Namespace)级别,跨...

    mybatis二级缓存扩展-与redis集成

    二级缓存的工作原理是:当某次查询的结果被缓存后,后续相同查询可以直接从缓存中获取,无需再次执行SQL,从而提高了性能。 集成Redis作为二级缓存的优势在于,Redis是一款高效的内存数据结构存储系统,支持多种...

    缓存处理-mybatis层

    MyBatis作为一个优秀的持久层框架,提供了缓存机制来提升查询速度,减轻数据库负担。本文将深入探讨MyBatis层的缓存处理,以及如何在数据底层进行优化。 首先,我们要理解MyBatis的缓存分为一级缓存和二级缓存。一...

    MyBatis 二级缓存 关联刷新实现

    也就是针对于同一事务,多次执行同一Mapper的相同查询方法,第一查询后,MyBatis会将查询结果放入缓存,在中间不涉及相应Mapper的数据更新(Insert,Update和Delete)操作的情况下,后续的查询将会从缓存中获取,而...

    springboot+mybatis+ehcache实现缓存数据

    例如,调用`getUserById`方法多次,观察是否每次都从缓存中获取数据,以及在缓存过期后是否重新从数据库加载。 总结,通过SpringBoot、MyBatis和Ehcache的结合,我们可以实现高效的本地缓存机制,提高数据读取速度...

    Mybatis延迟加载和缓存(基于XML配置).zip

    一级缓存在SqlSession级别,同一个SqlSession内的多次相同查询会复用第一次查询的结果,避免重复的数据库访问。而二级缓存则在Mapper级别,多个SqlSession之间可以共享缓存数据。 1. **一级缓存** - 默认启用,...

    MyBatis一级缓存避坑完全指南

    一级缓存的概念是指在MyBatis的一次会话中,缓存查询结果,以便下次查询时直接从缓存中取出结果,而不需要再次查询数据库。这样可以减少数据库查询的次数,提高系统的性能。 MyBatis的一级缓存有两种级别:SESSION...

    三,MyBatis动态SQL,缓存和分页插件, Lombok工具

    MyBatis提供了两级缓存:一级缓存默认存在于SqlSession级别,同一个SqlSession内的多次相同查询会直接从缓存获取结果;二级缓存则可跨SqlSession,它是基于namespace的,需要在配置文件中开启,并在Mapper接口或XML...

    Mybatis缓存测试示例

    一级缓存是SqlSession级别的,同一SqlSession内的多次相同查询会复用之前的查询结果,避免了重复的数据库访问。而二级缓存则是Mapper(或Namespace)级别的,它可以跨SqlSession共享数据,提高了数据读取效率。 一...

    实现Mybatis框架中一对多关联映射的查询操作。

    本篇将详细讲解如何在Mybatis中实现一对多关联映射的查询操作。 首先,我们要明确一对多关联映射的基本概念。在这个例子中,User表(用户表)和Order_form表(订单表)之间存在1-N的关系,意味着一个用户可以有多个...

    Mybatis的缓存1

    1. 当执行一次查询操作时,Mybatis会检查一级缓存中是否存在对应的结果。 2. 若缓存中不存在,则执行SQL,从数据库获取结果,并将结果存入一级缓存。 3. 如果后续有相同查询请求,Mybatis会在一级缓存中查找,发现...

    mybatis3--延迟加载,缓存

    1. **一级缓存(Local Cache)**:一级缓存是 SqlSession 级别的缓存,同一个 SqlSession 内的多次查询,如果查询的是相同的 SQL,MyBatis 会直接从缓存中获取结果,而不会再次执行 SQL。但是,当 SqlSession 关闭或...

    mybatis源码分析笔记

    MyBatis的二级缓存是指在多个SqlSession之间共享缓存。MyBatis的二级缓存可以解决一级缓存无法处理并发情况的问题。MyBatis的二级缓存的工作流程如下: 1. MyBatis在执行Sql语句时,会首先检查二级缓存中是否存在...

    Mybatis源码分析七之Cache缓存.pdf

    需要注意的是,一级缓存对于不同事务或者不同Session是隔离的,也就是说,同一个SqlSession内的多次查询可以复用缓存,但不同SqlSession之间无法共享。此外,如果在同一个SqlSession内修改了数据并提交事务,那么在...

    mybatis关联查询多对多查询案例

    6. **查询优化**:在实际应用中,我们还需要关注性能问题,如是否需要缓存结果,以及如何避免N+1查询问题。有时,通过一次性获取所有关联数据,然后在内存中进行处理,可以提高查询效率。 在提供的压缩包文件...

    mybatis 的高级关联查询源码

    通过以上讲解,我们可以看到 MyBatis 在处理“一对多”关联查询时的灵活性和高效性。了解并熟练运用这些高级特性,可以大大提高我们的开发效率和代码质量。在实际项目中,结合缓存策略和事务管理,我们可以构建出...

Global site tag (gtag.js) - Google Analytics