Don’t understand mybatis first level cache? Let me tell you these five questions

Time:2021-2-26

L1 cache

Main contents:

Don't understand mybatis first level cache? Let me tell you these five questions

The first level cache is also called local cache. The first level cache of mybatis is cached at the session level. Mybatis’s first level cache is on by default. We don’t need to make any configuration in the development project, but if you want to close the first level cache, you can use localcachescopde = statement to close it.

How to turn off the first level cache?

In baseexecutor, see the following code:

Don't understand mybatis first level cache? Let me tell you these five questions

Why is it a sqlsession level cache?

The lifetime of the first level cache is the same as that of a sqlsession object.

In the following paragraph, the first level cache will be used.

`SqlSession sqlSession1 = sqlSessionFactory.openSession();
User user1 = sqlSession1.selectOne(“com.tian.mybatis.mapper.UserMapper.selectUserById”, 1);
User user2 = sqlSession1.selectOne(“com.tian.mybatis.mapper.UserMapper.selectUserById”, 1);
`

Results the output was as follows

Don't understand mybatis first level cache? Let me tell you these five questions

To sum up, two figures are used

The first time: check the database and put it into the cache.

Don't understand mybatis first level cache? Let me tell you these five questions

Second time: get it directly from the cache.

Don't understand mybatis first level cache? Let me tell you these five questions

The cache is not used in the following code

`SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
sqlSession = sqlSessionFactory.openSession();
sqlSession1 = sqlSessionFactory.openSession();
    
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
    
System.out.println (the “first query”);
System.out.println(userMapper.selectById(1));
    
User user = new User();
user.setUserName(“tian111”);
user.setId(1);
userMapper1.updateAuthorIfNecessary(user);
System.out.println (the “second query”);
System.out.println(userMapper.selectById(1));
`

Output results:

Don't understand mybatis first level cache? Let me tell you these five questions

To sum up, three figures are used

The first query: SQL session 1 queries the database and puts it into the cache.

Don't understand mybatis first level cache? Let me tell you these five questions

Update: update with sqlsession 2. Note that the local cache of sqlsession is written here.

Don't understand mybatis first level cache? Let me tell you these five questions

Second query: the second query of sqlsession 1.

Don't understand mybatis first level cache? Let me tell you these five questions

Remember that the first level cache can only be the same sqlsession object.

Where is the first level cache maintenance?

Since the life cycle of L1 cache is consistent with that of sqlsession, we can guess whether the cache is maintained in sqlsession?

The default implementation class of sqlsession is defaultsqlsession. In defaultsqlsession, only two properties can store the cache:

`private final Configuration configuration;
private final Executor executor;
`

Configuration is global and will not put the cache.

Then we can only place our hopes on the executor. Since executor is an interface, we can take a look at its implementation class:

Don't understand mybatis first level cache? Let me tell you these five questions

In addition, there is a baseexecutor. You have to aim at all kinds of things. I saw something.

`public abstract class BaseExecutor implements Executor {
  private static final Log log = LogFactory.getLog(BaseExecutor.class);
  protected Transaction transaction;
  protected Executor wrapper;
  protected ConcurrentLinkedQueue<DeferredLoad> deferredLoads;
/ / familiar guy, basic cache
  protected PerpetualCache localCache;
  protected PerpetualCache localOutputParameterCache;
  protected Configuration configuration;
    
  protected int queryStack;
  private boolean closed;
    
  protected BaseExecutor(Configuration configuration, Transaction transaction) {
    this.transaction = transaction;
    this.deferredLoads = new ConcurrentLinkedQueue<>();
    this.localCache = new PerpetualCache(“LocalCache”);
    this.localOutputParameterCache = new PerpetualCache(“LocalOutputParameterCache”);
    this.closed = false;
    this.configuration = configuration;
    this.wrapper = this;
  }
    
}
`

Look at the baseexecutor class diagram

Don't understand mybatis first level cache? Let me tell you these five questions

So this proves that the cache is maintained in sqlsession.

When is the first level cache cleared?

After executing update, insert, delete, flushcache = true, commit, rollback LocalCacheScope.STATEMENT In other cases, the first level cache will be emptied.

`@Override
public void clearLocalCache() {
    if (!closed) {
      localCache.clear();
      localOutputParameterCache.clear();
    }
}
`

Update, the first level cache will be cleared. Both delete and insert call the update. It can be traced from the insert, update and delete methods of sqlsession.

Don't understand mybatis first level cache? Let me tell you these five questions

LocalCacheScope.STATEMENT The first level cache is emptied. In the query method of baseexecutor:

Don't understand mybatis first level cache? Let me tell you these five questions

When a transaction is committed and rolled back, the first level cache is cleared.

Don't understand mybatis first level cache? Let me tell you these five questions

When flushcache = true, the first level cache will be cleared.

Don't understand mybatis first level cache? Let me tell you these five questions

What is the first level cache key?

Don't understand mybatis first level cache? Let me tell you these five questions

The following is the creation process of the first level cache key

`@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());
    cacheKey.update(rowBounds.getOffset());
    cacheKey.update(rowBounds.getLimit());
    cacheKey.update(boundSql.getSql());
    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);
        } 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);
      }
    }
    if (configuration.getEnvironment() != null) {
    // issue #176
    cacheKey.update(configuration.getEnvironment().getId());
    }
    return cacheKey;
  }
`

id:com.tian.mybatis.mapper.UserMapper.selectById

Key generation strategy: ID + offset + limit + SQL + param value + environment ID. if these values are the same, the generated key will be the same.

Example:

Don't understand mybatis first level cache? Let me tell you these five questions

Summary of L1 cache

The lifecycle of the first level cache is consistent with that of the sqlsession object. So the cache is maintained in the property executor in sqlsession.

The first level cache is on by default. The first level cache can be turned off by modifying the configuration item.

There are several ways to clear the first level cache

  • update、insert、delete
  • flushCache=”true”
  • commit、rollback
  • LocalCacheScope.STATEMENT