MyBatis from entry to soil-the use of cache

This is the 11th article in mybatis series . If you haven't read the previous suggestions, first go to the [Java Tsukuba Fox] public account to view the previous articles for easy understanding and mastering.

What is caching?

Cache is a place where data is stored (called: Cache). When a program wants to read data, it will first get it from the cache and return it directly. Otherwise, it will get it from other storage devices. The most important thing about the cache is to get it from the cache. The speed of internal data acquisition is very fast, and the data access speed can be accelerated through the cache. For example, when we get data from db, it takes time to transmit data through the network, db server takes time to read data from disk, etc. If these data are directly placed in the memory corresponding to the jvm, will the access be much faster?

Cache in mybatis

Mybatis is divided into first-level cache and second-level cache.

  • The first level cache is the SqlSession level cache. When operating the database, you need to construct a sqlSession object. There is a data structure (HashMap) in the object to store cache data. The cache data area (HashMap) between different sqlSessions does not affect each other. of.
  • The second-level cache is a mapper-level cache. Multiple SqlSessions operate on the same Mapper's SQL statement. Multiple SqlSessions can share the second-level cache. The second-level cache is across SqlSessions.

Level 1 cache

The first level cache is a SqlSession level cache. Each SqlSession has its own separate level one cache. The level one caches between multiple SqlSessions are isolated from each other and do not affect each other. The first level cache in mybatis is automatically turned on by default.

The working principle of the first level cache: in the same SqlSession to execute the same query multiple times, each time it is executed, it will be searched in the first level cache first, if there is in the cache, it will return directly, if there is no relevant data in the first level cache , Mybatis will go to the db to search, and then put the found data into the first-level cache. When the same query is executed the second time, it will find that it already exists in the cache and will return directly. The storage medium of the first level cache is memory, and a HashMap is used to store data, so the access speed is very fast.

First level cache case

Case sql script
DROP DATABASE IF EXISTS `mybatisdemo`;
CREATE DATABASE `mybatisdemo`;
USE `mybatisdemo`;
DROP TABLE IF EXISTS user;
CREATE TABLE user(
  id int AUTO_INCREMENT PRIMARY KEY COMMENT '用户id',
  name VARCHAR(32) NOT NULL DEFAULT '' COMMENT '用户名',
  age SMALLINT NOT NULL DEFAULT 1 COMMENT '年龄'
) COMMENT '用户表';
INSERT INTO t_user VALUES (1,'Java冢狐',18),(2,'Java',100),(3,'冢狐',23);
The following is to query user information and return a list
<select id="getList1" resultType="com.zhonghu.chat12.demo9.model.UserModel" parameterType="map">
    SELECT id,name,age FROM user
    <where>
        <if test="id!=null">
            AND id = #{id}
        </if>
        <if test="name!=null and name.toString()!=''">
            AND name = #{name}
        </if>
        <if test="age!=null">
            AND age = #{age}
        </if>
    </where>
</select>
Corresponding mapper interface method
List<UserModel> getList1(Map<String, Object> paramMap);
Test case
com.zhonghu.chat12.demo9.Demo9Test#level1CacheTest1
/**
 * 一级缓存测试
 *
 * @throws IOException
 */
@Test
public void level1CacheTest1() throws IOException {
    String mybatisConfig = "demo9/mybatis-config.xml";
    this.before(mybatisConfig);
    try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //第一次查询
        List<UserModel> userModelList1 = mapper.getList1(null);
        log.info("{}", userModelList1);
        //第二次查询
        List<UserModel> userModelList2 = mapper.getList1(null);
        log.info("{}", userModelList2);
        log.info("{}", userModelList1 == userModelList2);
    }
}

The above code is executed twice in the same SqlSession to obtain user list information, and the results of the two queries are placed in userModelList1 and userModelList2 respectively. The final code will also determine whether the two collections are equal. Let’s run it and see if we will access it. Several db.

Run output
01:15.312 [main] DEBUG c.j.c.d.mapper.UserMapper.getList1 - ==>  Preparing: SELECT id,name,age FROM user 
01:15.340 [main] DEBUG c.j.c.d.mapper.UserMapper.getList1 - ==> Parameters: 
01:15.364 [main] DEBUG c.j.c.d.mapper.UserMapper.getList1 - <==      Total: 3
01:15.364 [main] INFO  c.j.chat05.demo9.Demo9Test - [UserModel(id=1, name=Java冢狐, age=18), UserModel(id=2, name=Java, age=100), UserModel(id=3, name=冢狐, age=23)]
01:15.367 [main] INFO  c.j.chat05.demo9.Demo9Test - [UserModel(id=1, name=Java冢狐, age=18), UserModel(id=2, name=Java, age=100), UserModel(id=3, name=冢狐, age=23)]
01:15.367 [main] INFO  c.j.chat05.demo9.Demo9Test - true

It can be seen from the output that sql is only output once, indicating that the database will be accessed the first time, and the second time it will be directly obtained from the cache, and finally a true output is output, which also indicates that the two returned results are the same object. For the second time, the data is obtained directly from the cache, which speeds up the query.

3 ways to clear the first level cache

To query the same data in the same SqlSession, mybatis will get it from the first-level cache by default. If it is not in the cache, it will access the db. Then, if we want to directly access the database instead of the cache, what should we do?

There are 3 ways to invalidate the first level cache:

  • Add, delete, and modify operations in SqlSession, at this time sqlsession will automatically clean up its internal first-level cache
  • Call the clearCache method in SqlSession to clean up its internal first-level cache
  • Set the flushCache attribute value of the select element in Mapper xml to true, then all data in the first level cache will be cleared when the query is executed, and then go to the db to get the data

Any of the above methods will invalidate the current and cache in the SqlSession, and then go to the db to get the data.

Summary of Level 1 Cache Usage

  • The first level cache is at the SqlSession level. Each SqlSession has its own level one cache. The level one caches between different SqlSessions are isolated from each other.
  • The first level cache in mybatis is automatically turned on by default
  • When the same query is executed in the same SqlSession, it will first search from the first level cache, if it is found, it will return directly, if it is not found, it will visit the db, and then drop the data returned by the db into the first level cache. Get it directly from the cache during the second query
  • Three ways to clear the first-level cache (1: adding, deleting and modifying the SqlSession will invalidate the first-level cache; 2: calling the SqlSession.clearCache method will invalidate the first-level cache; 3: setting the flushCache attribute of the select element in the Mapper xml to true, then executing this query will invalidate the first level cache)

Secondary cache

Use of secondary cache

There are limitations in the use of the first-level cache. The same query must be executed in the same SqlSession, and the first-level cache can improve the query speed. If you want to use the cache between different SqlSessions to speed up the query, we need to use it at this time The second level cache.

The second-level cache is a mapper-level cache. Each mapper xml has a namespace, and the second-level cache is bound to the namespace. Each namespace is associated with a second-level cache. Multiple SqlSessions can share the second-level cache. The second-level cache is across SqlSessions. of.

The second level cache is not enabled by default, and we need to enable it in the mybatis global configuration file:

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

After the above configuration is completed, the following configuration needs to be added to the corresponding mapper xml to indicate that the query in this mapper opens the second-level cache:

<cache/>

The configuration is that simple.

Query principle when the first and second caches coexist

If both the primary and secondary caches are enabled, the data query process is as follows:

  • When a query is initiated, mybatis will first access the second-level cache corresponding to this namespace, and if there is data in the second-level cache, it will return directly, otherwise continue down
  • Query whether there is corresponding data in the first-level cache, if there is, return directly, otherwise continue down
  • Access the db to obtain the required data, and then put it in the secondary cache corresponding to the current SqlSession, and store a copy in another place in the local memory (this place is called TransactionalCache)
  • When SqlSession is closed, that is, when the close method of SqlSession is called, the data in TransactionalCache will be placed in the second-level cache, and the data in the current SqlSession first-level cache will be cleared.

Second-level cache case

The mybatis global configuration file opens the secondary cache configuration
<settings>
    <!-- 开启二级缓存 -->
    <setting name="cacheEnabled" value="true"/>
</settings>
Use the cache element in mapper xml to enable the second level cache
<!-- 启用二级缓存 -->
<cache/>
<select id="getList1" resultType="com.zhonghu.chat12.demo9.model.UserModel" parameterType="map">
    SELECT id,name,age FROM user
    <where>
        <if test="id!=null">
            AND id = #{id}
        </if>
        <if test="name!=null and name.toString()!=''">
            AND name = #{name}
        </if>
        <if test="age!=null">
            AND age = #{age}
        </if>
    </where>
</select>
Test case
com.zhonghu.chat12.demo9.Demo9Test#level2CacheTest1
/**
 * 二级缓存测试
 *
 * @throws IOException
 */
@Test
public void level2CacheTest1() throws IOException {
    String mybatisConfig = "demo9/mybatis-config1.xml";
    this.before(mybatisConfig);
    for (int i = 0; i < 2; i++) {
        try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            List<UserModel> userModelList1 = mapper.getList1(null);
            log.info("{}", userModelList1);
        }
    }
}

The above query is executed 2 times, and each query is a new SqlSession.

3 ways to clear or skip the secondary cache

When the second-level cache is turned on, after adding a cache element to a certain mapper xml, all queries in this mapper xml have the second-level cache enabled by default, so how do we clear or skip the second-level cache? The three ways are as follows:

  • Performing additions, deletions, and changes in the corresponding mapper will clear the data in the secondary cache
  • If the flushCache attribute of the select element is set to true, the data in the second-level cache will be cleared, then the data will be queried in the db, and then the data will be placed in the second-level cache
  • The useCache attribute of the select element is set to true, which can make this query skip the second-level cache and then query the data

to sum up

  • First-level and second-level cache access sequence: When both first-level and second-level caches exist, the second-level cache will be accessed first, then the first-level cache will be accessed, and the db will be accessed at the end. Let us understand this sequence.

  • Set the flushCache attribute of the select element in the mapper xml to false, and all data in the first-level cache will be cleared eventually, and all data in the second-level cache corresponding to the namespace where the select is located will be cleared

  • Set the useCache of the select element in the mapper xml to false, which will cause this query to skip the secondary cache

  • Generally speaking, the use of caching can improve query efficiency. If you master this knowledge, you can choose according to your business.

    At last

    • If you feel that you are rewarded after reading it, I hope to pay attention to it. By the way, give me a thumbs up. This will be the biggest motivation for my update. Thank you for your support.
    • Welcome everyone to pay attention to my public account [Java Fox], focusing on the basic knowledge of java and computer, I promise to let you get something after reading it, if you don’t believe me, hit me
    • Seek one-click triple connection: like, forward, and watching.
    • If you have different opinions or suggestions after reading, please comment and share with us. Thank you for your support and love.

    ——I am Chuhu, and I love programming as much as you.

Welcome to follow the public account "Java Fox" for the latest news

Guess you like

Origin blog.csdn.net/issunmingzhi/article/details/114269368