为什么 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);
}

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

7万+

被折叠的 条评论
为什么被折叠?



