Mybatis's first-level cache and second-level cache

What is cache

The cache is actually temporary data stored in the memory. The amount of data here will be relatively small. Generally speaking, the memory of the server is also limited. It is impossible to put all the data in the memory of the server. Therefore, only the key The data is put in the cache, which is famous for its fast speed and ease of use!

Why do you need caching

In the BS architecture, all user operations are additions, deletions, and changes to the database. Among them, the query operations are the most. But if the user wants to query a certain data every time, this will undoubtedly increase the pressure on the database, and Obtaining time efficiency will also be reduced, so in order to solve these problems, cache applications were born. After using the cache, the server only needs to query the database once, and then save the data in the memory of the server host, and then directly fetch it from the memory when it is read later. You don’t need to check the database every time. This solution not only reduces the database pressure, but also improves the response speed. It kills two birds with one stone.

What data will be put in the cache

Under normal circumstances, the data that is less changed and frequently used will be placed in the cache, such as dictionaries, system parameters, status codes with fixed values, etc.; in addition, saving users to the cache is also a good idea Strategies, so that you can respond quickly when you log in;

mybatis first level cache

The cache of mybatis is divided into two categories, namely the first level cache and the second level cache. The first level cache is turned on by default. All query operations in a sqlSession session will be saved in the cache. Generally speaking, all the queries in a request Add, delete, modify, and check operations are all in the same sqlSession, so we can think that each request has its own first-level cache. If there is an insert, update, or delete statement between two queries in the same sqlSession session, then the previous query All caches of will be cleared;

 Reader reader = Resources.getResourceAsReader("config/configuration.xml");        //创建数据工厂        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();        SqlSessionFactory sqlSessionFactory = builder.build(reader);        SqlSession sqlSession = sqlSessionFactory.openSession(true);          // 。。。。。。         // 这中间所走的所有查询操作都会进行缓存,一旦关闭sqlSession会话,缓存则会刷新         //释放会话        sqlSession.clearCache();        // 关闭会话        sqlSession.close();

Level 1 cache flow chart

Let's test it

Add the following configuration to the configuration file of mybatis, open the sql log, each sql represents a request for the database, so that we can judge whether the cache is used according to the sql

  <settings>        <!--标准的日志工厂实现类,打印sql日志-->        <setting name="logImpl" value="STDOUT_LOGGING"/>    </settings>

Sample code

public static void main(String[] args) throws IOException {         // 加载mybatis配置文件        Reader reader = Resources.getResourceAsReader("config/configuration.xml");        //创建数据工厂        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();        SqlSessionFactory sqlSessionFactory = builder.build(reader);        SqlSession sqlSession = sqlSessionFactory.openSession(true);          // 获取mapper接口对象        UserMapper mapper = sqlSession.getMapper(UserMapper.class);         // 查询第一次        User user = mapper.selectByPrimaryKey("3rfrf34r34");        // 第二次查询        User user1 = mapper.selectByPrimaryKey("3rfrf34r34");        System.out.println("两个user对象是否相等:"+(user == user1));        //释放会话        sqlSession.clearCache();        sqlSession.close();    }

Print result

According to the results, we can see that two queries were executed in the code, but the database was only queried once in the actual runtime, and the data was directly read from the cache the second time the data was retrieved, and the data read two times were the same. Here, the first level cache is already in effect;

Next, let’s test the second case: query -> modify -> query

Example code

 public static void main(String[] args) throws IOException {         // 加载mybatis配置文件        Reader reader = Resources.getResourceAsReader("config/configuration.xml");        //创建数据工厂        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();        SqlSessionFactory sqlSessionFactory = builder.build(reader);        SqlSession sqlSession = sqlSessionFactory.openSession(true);          // 获取mapper接口对象        UserMapper mapper = sqlSession.getMapper(UserMapper.class);        // 查询第一次        User user = mapper.selectByPrimaryKey("3rfrf34r34");                // 修改        mapper.updateByPrimaryKey(user);        // 第二次查询        User user1 = mapper.selectByPrimaryKey("3rfrf34r34");        System.out.println("两个user对象是否相等:"+(user == user1));        //释放会话        sqlSession.clearCache();        sqlSession.close();    }

Print result

The console printed sql three times. The first query and the third query are the same, but the cache is not used. Why is this happening? Because each addition, deletion, and modification operation may change the original data, the cache must be refreshed;

Secondary cache

The second-level cache is global, that is to say; multiple requests can share the same cache, and the second-level cache needs to be manually turned on. There are two ways to configure the second-level cache,

  • The cache will be placed in the first-level cache first, and the first-level cache will be flushed to the second-level cache when the sqlSession session is submitted or closed;
  • After the second-level cache is enabled, when users query, they will first go to the second-level cache, but if they can't find it, they will go to the first-level cache;

Second-level cache flow chart

The first configuration method

For a single mapper configuration, the main need to add the following configuration to the mapper.xml file that needs to open the secondary cache to enable

 <!-- 开启单个mapper的二级缓存,也叫全局缓存-->  <cache />

Note that it must be added to the xxMapper.xml file, do not add to the main configuration file of mybatis, it will report an error

The second configuration method

All mappers have the second level cache enabled, just add the following configuration in mybatis.xml

 <settings>        <!--  开启所有mapper的二级缓存 -->        <!--<setting name="cacheEnabled" value="true" />-->    </settings>

Sample code

     public static void main(String[] args) throws IOException {         // 加载mybatis配置文件        Reader reader = Resources.getResourceAsReader("config/configuration.xml");        //创建数据工厂        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();         SqlSessionFactory sqlSessionFactory = builder.build(reader);         // 第一个会话        SqlSession sqlSession = sqlSessionFactory.openSession(true);          // 获取会话一的mapper接口对象        UserMapper mapper = sqlSession.getMapper(UserMapper.class);         // 第一次查询        User user = mapper.selectByPrimaryKey("3rfrf34r34");                //释放第一个会话        sqlSession.clearCache();        sqlSession.close();        // 第二个会话        SqlSession sqlSession2 = sqlSessionFactory.openSession(true);        // 获取会话二的mapper接口对象        UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);        // 第二次查询        User user1 = mapper2.selectByPrimaryKey("3rfrf34r34");        // 释放第二个会话        sqlSession2.clearCache();        sqlSession2.close();    }

Print result

The print result is obvious, 2 queries, but the log shows that the database was only queried once, and the second time was the data obtained from the cache. So far, the secondary cache has been turned on!

Precautions

In addition, the cache has the following situations that need attention

  • The results of all select statements in the mapping statement file will be cached.
  • All insert, update, and delete statements in the mapped statement file will refresh the cache.
  • The cache will use the least recently used algorithm (LRU, Least Recently Used) algorithm to clear unnecessary cache.
  • The cache is not refreshed regularly (that is, there is no refresh interval).
  • The cache will hold 1024 references to lists or objects (regardless of which query method returns).
  • The cache is considered a read/write cache, which means that the acquired object is not shared and can be safely modified by the caller without interfering with potential modifications made by other callers or threads.