mybatis缓存

99 阅读4分钟

一级缓存

mybatis中一级缓存也叫做本地缓存,一级缓存是在会话也就是SqlSession层面实现的,一级缓存的作用范围是在同一个SqlSession中,不同的SqlSession即使查询相同的数据也不会走缓存。

一级缓存如何开启

一级缓存默认是开启的

一级缓存范围

mybatis一级缓存的范围有SESSION和STATEMENT两种,默认是SESSION。 如果不想使用一级缓存,可以把一级缓存的范围指定为STATEMENT,这样每次执行完一个Mapper中的语句后都会将一级缓存清除。 如果需要更改一级缓存的范围,可以在Mybatis的配置文件中,通过localCacheScope指定。

<setting name="localCacheScope" value="STATEMENT"/>

一级缓存命中原则?/mybatis怎么判断某两次查询是完全相同的查询?

条件1:要求查询的StatementId必须相同,否则无法命中缓存,即使两个查询语句、参数等完全一样。

image.png 条件2:要求传递给SQL的查询参数必须相同,否则无法命中缓存

image.png 条件3:要求分页参数必须相同,否则无法命中缓存

image.png 条件4:要求传递给JDBC的SQL必须完全相同

image.png 条件5:要求执行的环境相同:比如测试环境、生产环境

image.png

构成以上五个条件的代码逻辑:

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()); // 条件1 Mapper Id  例子:com.blog4java.mybatis.example.mapper.UserMapper.listAllUser
  cacheKey.update(rowBounds.getOffset()); // 偏移量 (分页参数) 条件3
  cacheKey.update(rowBounds.getLimit()); // 条数 (分页参数)    条件3
  cacheKey.update(boundSql.getSql()); // 条件4 SQL语句
  List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
  TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry();
  //条件2  所有参数值
  for (ParameterMapping parameterMapping : parameterMappings) {
    if (parameterMapping.getMode() != ParameterMode.OUT) {
      Object value;
      String propertyName = parameterMapping.getProperty();
      if (boundSql.hasAdditionalParameter(propertyName)) {
        value = boundSql.getAdditionalParameter(propertyName);
      } else if (parameterObject == null) {
        value = null;
      } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
        value = parameterObject;
      } else {
        MetaObject metaObject = configuration.newMetaObject(parameterObject);
        value = metaObject.getValue(propertyName);
      }
      cacheKey.update(value);
    }
  }
  // Environment Id   条件5
  if (configuration.getEnvironment() != null) {
    cacheKey.update(configuration.getEnvironment().getId());
  }
  return cacheKey;
}

一级缓存什么时候销毁?

  1. 在执行SqlSession.commit()之后,缓存会被清空,第二次查询会查询数据库

image.png 2. 在执行SqlSession.rollback()之后,缓存会被清空,第二次查询会查询数据库

image.png 3. 在执行insert、update、delete操作之后,缓存会被清空,第二次查询会查询数据库

image.png 4. 在执行SqlSession.clearCache之后,缓存会被清空,第二次查询会查数据库

image.png 5、SqlSession关闭,即执行SqlSession.close()方法会清空缓存

一级缓存工作原理

一级缓存是Mybatis中默认开启的缓存,它是在SqlSession的生命周期内有效的,也就是说,当我们从SqlSessionFactory中获取SqlSession对象,执行SQL语句后,查询到的结果会被缓存到该SqlSession对象的缓存中。当我们再次执行相同的SQL语句时,Mybatis会先从缓存中查找结果,如果存在则直接返回缓存中的数据,否则再去数据库中查询。 Mybatis的一级缓存是基于HashMap实现的,缓存的Key是SQL语句以及该语句所使用的参数,缓存的value是查询到的结果集。当我们执行查询语句时,Mybatis会先在缓存中查找是否存在相同的key,如果存在,则直接返回缓存中的value,否则再去执行SQL语句。当我们修改或删除数据时,Mybatis会自动将该SqlSession对象的缓存清空,以避免数据不一致的问题。 一级缓存是基于SqlSession对象实现的,因此,当我们执行多个SqlSession对象时,每个SqlSession对象都会有自己的一级缓存,它们之间互不干扰。这也意味着,如果我们执行了多个SqlSession对象,且每个对象执行了相同的查询语句,那么每个SqlSession对象都会去数据库中查询数据,而不会从其他SqlSession对象的缓存中获取数据。

二级缓存

二级缓存是Mapper级别的缓存,需要在Mybatis的配置文件中进行配置

二级缓存开启

开启二级缓存需要在mybatis-config.xml中配置:

<setting name="cacheEnabled" value="true"/>

二级缓存命中原则

同一级缓存命中原则

二级缓存清除

当执行增删改方法时会清除缓存

自定义缓存(redis实现)

这种缓存多用于分布式环境下使用,它通常借助于外部的分布式缓存系统,如redis或Memcached。这种缓存机制可以跨足多个应用服务器,实现分布式缓存共享。

使用mybatis整合redis实现分布式缓存

  1. pom坐标
        <dependency>
            <groupId>org.mybatis.caches</groupId>
            <artifactId>mybatis-redis</artifactId>
            <version>1.0.0-beta2</version>
        </dependency>

  1. application.properties 中配置
# 开启缓存
mybatis-plus.configuration.cache-enabled=true


##redis 配置
redis.host=localhost
redis.port=6379
redis.connectionTimeout=5000
redis.password= 
redis.database=0

  1. mapper.xml 文件中
<cache type="org.mybatis.caches.redis.RedisCache"/>