MyBatis 缓存原理解析

本文详细解析了MyBatis中的一级缓存(本地缓存)与二级缓存的工作原理,包括它们的启用方式、作用范围、缓存策略以及在事务中的处理。重点讲解了一级缓存在SqlSession层面的实现和二级缓存的开启与注意事项。

为什么 MyBatis 要缓存

缓存在互联网系统中是非常重要的, 其主要作用是将数据保存到内存中, 当用户查询数据时, 优先从缓存容器中获取数据,而不是频繁地从数据库中查询数据,从而提高查询性能。而在 ORM 框架中引入缓存的目的就是为了减少读取数据库的次数,从而提升查询的效率。

在 MyBatis 中存在两种缓存,一个在事务内部使用的一级缓存,另一个可以全局使用的二级缓存。

一级缓存

一级缓存也叫本地缓存,在MyBatis中,一级缓存是在会话(SqlSession)层面实现的,这就说明一级缓存作用范围只能在同一个 SqlSession 中,跨 SqlSession 是无效的。

需要注意的是:MyBatis 中一级缓存是默认开启的,不需要任何的配置。

既然一级缓存的作用域只对同一个 SqlSession 有效,那么一级缓存应该存储在哪里比较合适是呢?

当然是 SqlSession 内是最合适的,下面我们看看 SqlSession 的唯一实现类 DefaultSqlSession,如下图所示:
在这里插入图片描述
我们知道,SqlSession 只提供对外接口,实际执行 sql 的就是 Executor。
下面是查询的执行流程:

在这里插入图片描述每个 SqlSession 实例中都有一个 Executor 对象,Executor 对象执行查询操作。

Executor有多个实现,无论哪种实现,查询的时候都会执行父类 BaseExecutor 的 query 方法。

  @Override
  public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
   
   
    //获取SQL
    BoundSql boundSql = ms.getBoundSql(parameter);
    CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);//创建一级缓存
    return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
  }

从这里我们可以看到,在查询之前就会去 localCache 中根据 CacheKey 对象来获取缓存,获取不到才会调用下面的 query 方法中的 queryFromDatabase 方法。

接下来看一下缓存的 key 是怎么创建的。
缓存的 key 使用 CacheKey 表示。MyBatis 使用 createCacheKey 方法创建 CacheKey 对象,如下所示:

  @Override
  public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {
   
   
    if (closed) {
   
   
      throw new ExecutorException("Executor was closed.");
    }
    CacheKey cacheKey = new CacheKey();
    cacheKey.update(ms.getId());//Mapper接口的全限定类名+方法名
    cacheKey.update(rowBounds.getOffset());//查询数据的偏移量
    cacheKey.update(rowBounds.getLimit());//查询条数
    cacheKey.update(boundSql.getSql());//原始SQL语句
    List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
    TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry();
    // mimic DefaultParameterHandler logic
    for (ParameterMapping parameterMapping : parameterMappings) {
   
   
      if (parameterMapping.getMode() != ParameterMode.OUT) {
   
   
        Object value;
        String propertyName = parameterMapping.getProperty();
        if (boundSql.hasAdditionalParameter(propertyName)) {
   
   
          value = boundSql.getAdditionalParameter(propertyName);
        }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值