Implementation of mybatis first level cache and second level cache

Time:2021-4-27

This paper introduces the implementation of the system

First level cache:

It meansSqlSession. The scope of the first level cache is a sqlsessionMybatisThe first level cache is on by default

In the same sqlsessionExecute the same SQL queryFor the first time, query the database and write it to the cache; The second time it is fetched directly from the cache. When executing SQLWhen the operation of adding, deleting and modifying occurs between the two queries, the sqlsessionThe cache is cleared.


L2 cache:

It meansmapperMapping file. The scope of L2 cache is the same namespaceMapper underMapping file content, multiple sqlsessionsshare.MybatisYou need to set the secondary cache manually

In the same namespaceMapper underFile, execute the same SQL queryFor the first time, query the database and write it to the cache; The second time it is fetched directly from the cache. When executing SQLIf the operation of adding, deleting and modifying occurs between the two queries, the L2 cache will be cleared.


 

1、 Lifetime of L1 cache:

1. When mybatis starts a session, it creates sqlsession object, excutor object and perpetual cache object.

2. Call the close() method at the end of the session or sqlsession to release the three created objects.

3. If sqlsession calls clearcache () method, it will clear all the first level cache. When the object still exists, it can be reused.

4. When sqlsession performs modify delete add operation, it will empty the perlualcache object.

 


 

2、 L2 cache expiration time:

1. The second level cache has an expiration time, which is not the expiration time of key value, but the expiration time of this cache. It is flushinterval, which means that the entire cache is cleared, so there is no need for the background thread to regularly detect.

2. Whenever accessing data, check the lifetime of the cache. The default is 1 hour. If the cache survives for one hour, clear the whole cache.

be careful:

Because the data of L2 cache is not always stored in memory, and its storage media are various, it is necessary to serialize the cached objects.

If the class has a parent class, the parent class also implements serialization.


 

First level cache implementation:

Build mybatis environment:

1.db.properties

1 jdbc.driver=com.mysql.jdbc.Driver
2 jdbc.url= jdbc:mysql :// localhost:3306/ (database)
3 jdbc.username=root
4 jdbc.password=123456

 

2.mybatis-config.xml

1 
 2          PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
 4         "http://mybatis.org/dtd/mybatis-3-config.dtd">
 5 
 6     
 7     
 8     
 9         
10         
11     
12     
13     
14         
15     
16 
17     
18     
19         
20             
21             
22             
23             
24                 
25                 
26                 
27                 
28             
29         
30     
31     
32         
33         
34     
35

 

3.userMapper.xml

1 
 2          PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 4         "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 5 
 6     
 7         SELECT
 8         id id,
 9         username username,
10         userpwd userpassword
11         FROM
12         user
13     
14

 

4. Interface usermapper

1 package com.Charon.dao;
 2 
 3 import com.Charon.enty.User;
 4 
 5 import java.util.List;
 6 
 7 /**
 8  * @Description TODO
 9  * @Author Charon <[email protected]>
10  * @create 2020-10-27-21:44
11  * @Version 1.0.0
12  */
13 public interface UserMapper {
14 // query database user information
15     List findUserAll();
16 }

 

5. Entity class

**
 *@ description todo user entity class
 * @Author Charon <[email protected]>
 * @create 2020-10-27-21:37
 * @Version 1.0.0
 */
public class User {
    private Integer id;
    private String username;
    private String userpassword;
    
    //The getter and server methods are omitted        
}

 

6. Tools

1 package com.Charon.utile;
 2 
 3 import org.apache.ibatis.io.Resources;
 4 import org.apache.ibatis.session.SqlSession;
 5 import org.apache.ibatis.session.SqlSessionFactory;
 6 import org.apache.ibatis.session.SqlSessionFactoryBuilder;
 7 
 8 import java.io.IOException;
 9 import java.io.InputStream;
10 import java.io.Reader;
11 
12 /**
13 * @ description todo agent factory class
14  * @Author Charon <[email protected]>
15  * @create 2020-10-21-8:59
16  * @Version 1.0.0
17  */
18 public class MyBatisUtil {
19 
20     private final  static SqlSessionFactory sqlSessionFactory;
21 
22     static {
23         String resource="mybatis-config.xml";
24         Reader reader =null;
25         try {
26             reader = Resources.getResourceAsReader(resource);
27         } catch (IOException e) {
28             e.printStackTrace();
29         }
30         sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
31     }
32 
33     /**
34 * get sqlsessionfactory
35      * @return SqlSessionFactory
36      */
37     public static SqlSessionFactory getSqlSessionFactory(){
38         return sqlSessionFactory;
39     }
40 
41     /**
42 * get sqlsession
43      * @return SqlSession
44      */
45     public static SqlSession getSqlSession(){
46         return sqlSessionFactory.openSession();
47     }
48 
49     /**
50 * close sqlsession
51      */
52     public  static void closeSession(SqlSession sqlSession){
53         if (sqlSession!=null)
54             sqlSession.close();
55     }
56 }

 

7. Test, which calls two queries

@Test
    public void test() {
        SqlSession sqlSession = MyBatisUtil.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
       //First query
        List userAll = mapper.findUserAll();
        for (int i = 0; i < userAll.size(); i++) {
            User user = userAll.get(i);
            System.out.println(user);
        }
       //Second query
        List userAlls = mapper.findUserAll();
        for (int i = 0; i < userAlls.size(); i++) {
            User user = userAlls.get(i);
            System.out.println(user);
        }
    }

 

8. As a result, it can be seen from the running results that the current program only calls SQL once

 

9. Mask the first level cache

Add a condition to the usermapper. XML query

flushCache=true

 

 

 10. Show the effect after masking the first level cache

 


 

Implementation of L2 cache

1. Set in mybatis-config.xml

 

2. Interface usermapper

1 package com.Charon.dao;
 2 
 3 import com.Charon.enty.User;
 4 
 5 import java.util.List;
 6 
 7 /**
 8  * @Description TODO
 9  * @Author Charon <[email protected]>
10  * @create 2020-10-27-21:44
11  * @Version 1.0.0
12  */
13 public interface UserMapper {
14 // query database user information
15     List findUserAll();
16 
17     void updateUser(User user);
18 }

 

4.userMapper.xml

1 
 2          PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 4         "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 5 
 6     
 7     
 8         SELECT
 9         id id,
10         username username,
11         userpwd userpassword
12         FROM
13         user
14     
15     
16         UPDATE user SET username=#{username},userpwd=#{userpassword} WHERE id=#{id}
17     
18     
19     
20

 

5. The entity class implements the serializable interface

package com.Charon.enty;

import java.io.Serializable;

/**
 *@ description todo user entity class
 * @Author Charon <[email protected]>
 * @create 2020-10-27-21:37
 * @Version 1.0.0
 */
public class User implements Serializable{
    private Integer id;
    private String username;
    private String userpassword;

    //Ignore getter setter method
}

 

6. Testing

 

7. Comment out the sqlsession and check the L2 cache

 

 8. annotate sqlsession3 to view the L2 cache

 


 

Other configurations (usecache and flushcache)

1. Mybatis can also configure configuration items such as usercache and flushcache.

2. Usecache is used to set whether to disable the secondary cache. Setting usecache = false in usermapper.xml can disable the secondary cache of the current select statement

, that is, each query will issue SQL to query, and the default is true, that is, the SQL uses the secondary cache.

Use demo

 

 

3.flushCache:

In this case, the latest data SQL is required for each query. To set usecache = false, disable the secondary cache and get it directly from the database.
In the same namespace of mapper, if there are other insert, update and delete operations, the cache needs to be refreshed. If the cache is not refreshed, dirty reading will occur.

Set the flushcache = “true” property in the statement configuration, which is true by default,

That is to refresh the cache. If it is changed to false, it will not be refreshed. When using cache, if you manually modify the query data in the database table, dirty reading will appear.

 

Generally, after the commit operation, the cache needs to be refreshed. Flushcache = true means to refresh the cache, which can avoid dirty reading of the database. So we don't need to set it, just by default