MyBatis level 1 cache implementation details and precautions

Keywords: Java Session Mybatis Database SQL

Introduction to L1 cache

In the process of application running, it is possible for us to execute multiple SQL queries with the same query conditions in a database session. MyBatis provides the scenario of optimizing the first level cache. If the SQL statements are the same, the first level cache will be hit first, so as to avoid directly querying the database and improve the performance. The specific implementation process is shown in the figure below.

The Executor executor is created in each SqlSession session session, and there is a Local Cache in each Executor. When the user initiates a query, MyBatis generates a MappedStatement based on the currently executed statement, queries in the Local Cache, and directly returns the result to the user if the cache hits, queries the database if the cache does not hit, writes the result to the Local Cache, and finally returns the result to the user.

L1 cache configuration

Let's see how to use the MyBatis L1 cache. Developers only need to add the following statement in MyBatis configuration file to use the first level cache. There are two options, SESSION or statement. The default is SESSION level, that is, all statements executed in a MyBatis SESSION will share this cache. One is the statement level, which can be understood as that the cache is only valid for the currently executed statement.

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

First level cache experiment

Open the first level cache. The scope is session level. Call getStudentById three times. The code is as follows:

public void getStudentById() throws Exception {
    SqlSession sqlSession = factory.openSession(true); // Auto commit transaction
    StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
    System.out.println(studentMapper.getStudentById(1)); // query data base
    System.out.println(studentMapper.getStudentById(1)); // Query cache
    System.out.println(studentMapper.getStudentById(1)); // Query cache
}
public void addStudent() throws Exception {
    SqlSession sqlSession = factory.openSession(true); // Auto commit transaction
    StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
    System.out.println(studentMapper.getStudentById(1)); // query data base
    System.out.println(studentMapper.addStudent(buildStudent())); // Update data
    System.out.println(studentMapper.getStudentById(1)); // query data base
    sqlSession.close();
}
public void testLocalCacheScope() throws Exception {
    SqlSession sqlSession1 = factory.openSession(true); 
    SqlSession sqlSession2 = factory.openSession(true); 

    StudentMapper studentMapper = sqlSession1.getMapper(StudentMapper.class);
    StudentMapper studentMapper2 = sqlSession2.getMapper(StudentMapper.class);

    System.out.println(studentMapper.getStudentById(1)); // query data base
    System.out.println(studentMapper.getStudentById(1)); // Query cache
    System.out.println(studentMapper2.updateStudentName("Little Cen",1)); // Update data
    System.out.println(studentMapper.getStudentById(1)); // Query cache, dirty data
    System.out.println(studentMapper2.getStudentById(1)); // query data base
}

First level cache workflow

The timing chart of L1 cache execution is shown in the figure below.

summary

  1. The life cycle of MyBatis L1 cache is consistent with SqlSession.
  2. The internal design of MyBatis first level cache is simple, but it is a HashMap without capacity limit, which lacks the functionality of cache.
  3. The maximum range of the first level cache of MyBatis is within the SqlSession. When there are multiple sqlsessions or distributed environments, the database write operation will cause dirty data. Therefore, it is recommended to set the cache level to Statement.

Posted by phpORcaffine on Sun, 26 Apr 2020 09:16:35 -0700