`
cjnetwork
  • 浏览: 179488 次
  • 性别: Icon_minigender_1
  • 来自: 重庆
社区版块
存档分类
最新评论

mybatis二级缓存工作机制

阅读更多
mybatis二级缓存工作机制

在mybatis的主配置文件中,启动二级缓存配置
    <settings>
        <setting name="cacheEnabled" value="true"/> 
    </settings>

    这个配置会再以后生成Executor的时候使用CachingExecutor而非 BaseExecutor

    然后在映射的xml配置文件如UserMapper.xml中 对该实体启用缓存,简单点写直接添加
<cache/>
即可。至此配置完成。


    在完成以上配置之后,对缓存进行测试
测试的核心代码
SqlSession session = sqlSessionFactory.openSession();
List<User> allUsers =  session.selectList("com.test.model.User.queryUserByName", "%test%", new RowBounds(1, 1));
session.commit();
List<User> allUsers3 = sqlSessionFactory.openSession().selectList("com.test.model.User.queryUserByName", "%test%", new RowBounds(1, 1));

    理论上将,这种方式查询数据请求,在mybatis中肯定是可以直接从二级缓存中取数据的。
    请看如下的图(网上找的,觉得还不错)。




    其中CachingExecutor类的query方法
public List query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    if (ms != null) {
      Cache cache = ms.getCache();
      if (cache != null) {
        flushCacheIfRequired(ms);
        cache.getReadWriteLock().readLock().lock();
        try {
          if (ms.isUseCache() && resultHandler == null) {
            CacheKey key = createCacheKey(ms, parameterObject, rowBounds);
            final List cachedList = (List) cache.getObject(key);
            if (cachedList != null) {
              return cachedList;
            } else {
              List list = delegate.query(ms, parameterObject, rowBounds, resultHandler);
              tcm.putObject(cache, key, list);
              return list;
            }
          } else {
            return delegate.query(ms, parameterObject, rowBounds, resultHandler);
          }
        } finally {
          cache.getReadWriteLock().readLock().unlock();
        }
      }
    }
    return delegate.query(ms, parameterObject, rowBounds, resultHandler);
  }

    查询请求来的时候,会首先从MappedStatement中取出缓存实例Cache,若开启了二级缓存的,则先从二级缓存中查找数据,找到即直接返回结果,若没有找到,则使用delegate(叫做代理业好,装饰器也好)所代理的查询(此处为BaseExecutor)来进行查询,代理的具体查询就不说了,不是本文的重点。结合上图以及代码,可以看出tcm.putObject(cache, key, list);这句话是将查询处理的结果放入缓存,其中tcm是在CachingExecutor中定义的private TransactionalCacheManager tcm = new TransactionalCacheManager();

    然后我们查看TransactionalCacheManager的putObject(cache, key, list)方法,如下
public class TransactionalCacheManager {
	private Map<Cache, TransactionalCache> transactionalCaches = new HashMap<Cache, TransactionalCache>();

  
  public void putObject(Cache cache, CacheKey key, Object value) {
    getTransactionalCache(cache).putObject(key, value);
  }

}


    继续查看TransactionalCache的源码,可以看到,在TransactionalCache的putObject(Object key, Object object)方法中,并不是直接将结果集合放入缓存中,而是加入到一个队列中,这个队列会再发起这次请求的SqlSession提交(commit)或关闭(close)的时候,调用到TransactionalCache的commit方法,从而调用到内部类AddEntry的commit方法,将结果集合存放到缓存中。
public class TransactionalCache implements Cache {
  private Cache delegate;
  private Map<Object, AddEntry> entriesToAddOnCommit;

public void putObject(Object key, Object object) {
    entriesToRemoveOnCommit.remove(key);
    entriesToAddOnCommit.put(key, new AddEntry(delegate, key, object));
  }

 public void commit() {
    delegate.getReadWriteLock().writeLock().lock();
    try {
      if (clearOnCommit) {
        delegate.clear();
      } else {
        for (RemoveEntry entry : entriesToRemoveOnCommit.values()) {
          entry.commit();
        }
      }
      for (AddEntry entry : entriesToAddOnCommit.values()) {
        entry.commit();
      }
      reset();
    } finally {
      delegate.getReadWriteLock().writeLock().unlock();
    }
  }


private static class AddEntry {
    private Cache cache;
    private Object key;
    private Object value;

    public AddEntry(Cache cache, Object key, Object value) {
      this.cache = cache;
      this.key = key;
      this.value = value;
    }

    public void commit() {
      cache.putObject(key, value);
    }
  }

}


    下图为将结果集合存入缓存的过程。


  • 大小: 27.9 KB
  • 大小: 77.6 KB
分享到:
评论
2 楼 xussen 2013-03-15  
还有似乎3.1.1开始,CachingExecutor将读写锁放到了delegate.query操作之前,
理由是为了防止死锁,// issue #578. Query must be not synchronized to prevent deadlocks
可以这样会不会有线程安全问题呢
1 楼 xussen 2013-03-15  
能否解释一下为何不把结果集直接放进缓存,而是放入队列当中,延迟缓存。
除了可以减少频繁的get,set的操作,是否还有跟线程安全有关系?

相关推荐

    深入理解MyBatis中的一级缓存与二级缓存

    一级缓存和二级缓存都是MyBatis提供的缓存机制,它们可以帮助提高应用程序的性能。但是,二级缓存的作用范围更大,可以被多个SqlSession共用,是一种更强大的一种缓存机制。 在实际开发中,MyBatis通常和Spring进行...

    mybatis一级缓存和二级缓存简单示例

    二级缓存是 Mapper 级别的缓存,可以跨 SqlSession 工作。它将数据存储在一个全局区域,多个 SqlSession 可以共享。二级缓存默认是关闭的,需要在 MyBatis 配置文件或 Mapper 映射文件中开启。开启二级缓存后,相同...

    mybatis二级缓存

    标题中的“mybatis二级缓存”指的是MyBatis框架中的一个重要特性,它是MyBatis缓存机制的一部分,用于提升数据库查询效率。MyBatis一级缓存是SqlSession级别的,而二级缓存则是在整个Mapper配置范围内的全局缓存,...

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

    在大型系统中,为了提高数据访问效率,MyBatis提供了二级缓存机制。本文将深入探讨如何对MyBatis的二级缓存进行扩展,并将其与Redis集成,以充分利用分布式缓存的优势。 MyBatis的二级缓存是基于全局的,它允许不同...

    springMybatis+redis三级缓存框架

    MyBatis的二级缓存机制允许我们将执行过的SQL查询结果存储在内存中,以供后续相同的查询直接使用,从而避免了重复的数据库访问。二级缓存可以配置在Mapper级别或全局级别,通过XML配置文件或注解进行设置。在实现二...

    MyBatis缓存(一级缓存、二级缓存)

    缓存是MyBatis性能优化的重要手段,分为一级缓存和二级缓存。在这篇文章中,我们将深入探讨这两个级别的缓存机制及其工作原理。 **一级缓存** 一级缓存是SqlSession级别的缓存,也称为局部缓存。当你执行一个查询...

    深入了解MyBatis二级缓存

    "深入了解MyBatis二级缓存" MyBatis是一种流行的Java持久层框架,它提供了强大的缓存机制以提高应用...通过了解MyBatis二级缓存的工作原理、配置方法和使用场景,可以更好地使用MyBatis二级缓存提高应用程序的性能。

    mybatis一二级缓存

    在 MyBatis 中,一级缓存和二级缓存是两个重要的性能优化手段,它们可以有效减少对数据库的访问,提高系统的响应速度。下面将详细阐述这两个缓存机制。 ### 一级缓存 一级缓存是 MyBatis 默认开启的本地会话缓存,...

    深入了解MyBatis二级缓存共6页.pdf.zip

    本文将深入探讨MyBatis的二级缓存机制,旨在帮助开发者更好地理解和利用这一功能。 首先,我们需要了解什么是缓存。缓存是一种存储技术,用于暂时保存经常访问的数据,以便快速获取,减少对数据库的直接访问,从而...

    MyBatis3开启二级缓存

    本篇将详细介绍如何在MyBatis3中启用二级缓存,并深入解析其工作原理和配置步骤。 **一、MyBatis缓存概念** MyBatis的缓存分为一级缓存和二级缓存。一级缓存是SqlSession级别的,同一个SqlSession内的相同SQL语句...

    mybatis二级缓存的实现代码

    MyBatis二级缓存的实现代码 MyBatis是当前Java领域中最流行的持久层框架之一,将SQL映射到Java对象的技术称为ORM(Object-Relational Mapping)。MyBatis提供了三级缓存机制,一级缓存是Session级别的缓存,二级...

    Mybatis-plus基于redis实现二级缓存过程解析

    为了解决这个问题,Mybatis-plus提供了基于Redis的二级缓存机制,能够大幅度提高应用程序的性能。 在Mybatis-plus中,二级缓存是指在应用程序中使用Redis作为缓存层,存储查询结果,以便下次查询时直接从缓存中获取...

    MyBatis-05 缓存机制

    本篇文章将详细探讨MyBatis的缓存机制,包括一级缓存和二级缓存,以及如何将MyBatis与第三方缓存EhCache进行整合。 首先,我们来了解一级缓存。一级缓存是SqlSession级别的,也称为本地缓存。当我们在一个...

    分布式系统架构——使用Redis做MyBatis的二级缓存 - CSDN博客1

    MyBatis的二级缓存机制允许开发者自定义缓存实现,这就为我们使用Redis这样的分布式缓存系统提供了可能。Redis是一个高性能的键值存储系统,适合存储大量的字符串、列表、集合、哈希表等数据结构,并支持丰富的操作...

    mybatis+redis实现二级缓存

    为了解决这个问题,MyBatis提供了二级缓存机制。一级缓存是SqlSession级别的,同一个SqlSession内的多次查询会复用已缓存的结果;而二级缓存则是Mapper级别的,可以在多个SqlSession之间共享,跨越了单一事务的限制...

    mybatis-plus 缓存(二)

    作为一名 IT 行业大师,我将对 Mybatis-Plus 缓存机制进行详细的解释,帮助读者深入了解缓存的概念、Mybatis-Plus 缓存机制的工作原理、一级缓存和二级缓存的配置和使用、缓存的优点和缺点等。 缓存是什么? 缓存是...

    详解Spring boot使用Redis集群替换mybatis二级缓存

    但是,MyBatis 的二级缓存机制存在一些缺陷,例如不支持集群模式、缓存数据不易管理等问题。因此,本文将介绍如何使用 Redis 集群来替换 MyBatis 的二级缓存机制,提高缓存机制的可扩展性和性能。 知识点1:Spring ...

    【MyBatis源码全面解析】MyBatis一二级缓存介绍

    MyBatis一二级缓存介绍 MyBatis是一款流行的Java持久层框架,它...MyBatis的一二级缓存机制可以大大提高数据库操作的性能,减少数据库查询的次数。但是,需要合理地配置缓存机制,避免缓存溢出和数据不一致的问题。

    mybatis+redis缓存配置

    本文重点介绍的是如何结合SpringMVC框架、MyBatis以及Redis实现一个高效的二级缓存机制。 #### 二、Redis作为二级缓存实现 Redis是一个开源的高性能键值存储系统,它具有内存存储、低延迟和丰富的数据结构等特点,...

    MyBatis关于二级缓存问题

    同时,MyBatis二级缓存对细粒度的数据级别的缓存实现不好,需要在业务层根据需求对数据有针对性缓存。 MyBatis关于二级缓存问题的解决方案提供了强大的缓存机制来提高应用程序的性能,但需要根据实际情况选择合适的...

Global site tag (gtag.js) - Google Analytics