mybatis多长查询缓存问题

MyBatis缓存机制
本文探讨了MyBatis框架中的缓存机制,特别是在同一事务内多次执行相同SQL查询时的行为。介绍了如何通过配置flushCache属性来控制缓存刷新,避免因缓存导致的数据不一致问题。
  最近在使用mybatis的过程中,发现一个问题。如果在同一个事物中,多次同一个查询sql在mybatis的执行过程中,只会查询一次数据库,后几次所返回的对象是mybatis在在内部做了缓存。

   
Java代码  收藏代码
  1.     Property property = this.findByPropertyId("123");  
  2. property.setPropertyId(null);;  
  3. property = this.findByPropertyId("123");  
  4. System.out.println(property.getPropertyId());  


   
    以上的代码,打印的结果为 null , 但是我们所期望的可能是 123 , 我不知道这是mybatis的一个bug还是故意这样去设计的.mybatis在执行查询语句的时候,会在本地做一份缓存信息.在BaseExecutor类中:
   


   
Java代码  收藏代码
  1. private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {  
  2. List<E> list;  
  3. localCache.putObject(key, EXECUTION_PLACEHOLDER);  
  4. try {  
  5.   list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);  
  6. finally {  
  7.   localCache.removeObject(key);  
  8. }  
  9. localCache.putObject(key, list);  
  10. if (ms.getStatementType() == StatementType.CALLABLE) {  
  11.   localOutputParameterCache.putObject(key, parameter);  
  12. }  
  13. return list;  


   
    可以看到在queryFromDatabase方法中,查询数据库返回结果之后,mybatis编制了一个cachekey的对象,作为key,返回结果作为value,放入了缓存当中(这个地方没有使用拷贝的函数,所以只要外部修改了值,内部缓存中的值信息也会被修改)

    之后再下次查询的时候,会依据一个判断,是否需要执行缓存信息,同样是在BaseExecutor类中.
   


Java代码  收藏代码
  1. @SuppressWarnings("unchecked")  
  2. public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {  
  3.   ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());  
  4.   if (closed) throw new ExecutorException("Executor was closed.");  
  5.   if (queryStack == 0 && ms.isFlushCacheRequired()) {  
  6.     clearLocalCache();  
  7.   }  
  8.   List<E> list;  
  9.   try {  
  10.     queryStack++;  
  11.     list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;  
  12.     if (list != null) {  
  13.       handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);  
  14.     } else {  
  15.       list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);  
  16.     }  
  17.   } finally {  
  18.     queryStack--;  
  19.   }  
  20.   if (queryStack == 0) {  
  21.     for (DeferredLoad deferredLoad : deferredLoads) {  
  22.       deferredLoad.load();  
  23.     }  
  24.     deferredLoads.clear(); // issue #601  
  25.     if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {  
  26.       clearLocalCache(); // issue #482  
  27.     }  
  28.   }  
  29.   return list;  
  30. }  
  31.      


    看到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的每次查询都会清空缓存后在执行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值