First level and second level cache of mybatis

Time:2020-11-12

First level cache

Mybatis supports caching, but by default, it only turns on level 1 caching, which is only relative to the same sqlsession. Therefore, when the parameters and SQL are exactly the same, we use the same sqlsession object to call a mapper method, and usually execute SQL only once, because after the first query using the session, mybatis will put it in the cache. When querying later, if there is no claim to refresh and the cache does not time out, sqlsession will take out the current cache Instead of sending SQL to the database again.

              First level and second level cache of mybatis

There is no need to say a little bit about why you want to use level 1 caching. But there are still a few problems we should pay attention to.

  1. How long is the lifecycle of L1 cache?

a. When mybatis opens a database session, it will create a new sqlsession object, and there will be a new executor object in the sqlsession object. The executor object holds a new perpetual cache object; when the session ends, the sqlsession object, its internal executor object and the perpetual cache object are also released.

b. If sqlsession calls the close() method, the first level cache is released, and the first level cache is not available.

c. If clearcache() is called by sqlsession, the data in the perpetual cache object will be cleared, but the object can still be used.

d. If any update operation (update(), delete(), insert()) is executed in sqlsession, the data of the perpetual cache object will be cleared, but the object can continue to be used

    2. How to judge whether two queries are identical queries?

According to mybatis, two queries are considered identical if the following conditions are identical.

2.1 the statementid passed in

2.2 result range of result set required in query

2.3. The result of this query will be passed to JDBC java.sql.Preparedstatement SQL statement string for( boundSql.getSql () )

2.4 pass to java.sql.Statement Parameter value to set

L2 cache:

Mybatis secondary cache is application level cache, which can improve the efficiency of database query and improve the performance of application.

The overall design of mybatis cache mechanism and the working mode of secondary cache

  First level and second level cache of mybatis

The second level cache on the sqlsessionfactory level is not enabled by default. The opening of the second level cache needs to be configured. When implementing the second level cache, mybatis requires that the returned POJO must be serializable. In other words, the serializable interface is required to be implemented. The configuration method is very simple. You only need to configure the mapping XML file to turn on the cache / >. If we configure the secondary cache, it means that:

  • All select statements in the map statement file will be cached.
  • The cache is flushed by the desired insert, update, and delete statements in the mapping statement file.
  • The cache is retrieved using the default least recently used (LRU) algorithm.
  • According to the schedule, such as no flush interval (CNFI has no refresh interval), the cache will not be refreshed in any chronological order.
  • The cache stores 1024 references to a list collection or object, regardless of what the query method returns
  • The cache is treated as a read / write cache, which means that object retrieval is not shared and can be modified safely by callees without interfering with potential modifications made by other callers or threads.

Practice:

1、 Create a POJO bean and serialize it

Since the data of the secondary cache is not always stored in memory, its storage media is various, so it is necessary to serialize the cached objects. (if it is stored in memory, the actual measurement can be done without serialization. )

package com.yihaomen.mybatis.model;

import com.yihaomen.mybatis.enums.Gender;
import java.io.Serializable;
import java.util.List;

/**
 *  @ProjectName: springmvc-mybatis 
 */
public class Student implements Serializable{

    private static final long serialVersionUID = 735655488285535299L;
    private String id;
    private String name;
    private int age;
    private Gender gender;
    private List<Teacher> teachers;
    setters&getters()....;
    toString();        
}

2、 Turn on L2 cache in mapping file

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yihaomen.mybatis.dao.StudentMapper">
    <! -- enable the secondary cache under the namespace of this mapper -- >
    <!--
        Eviction: represents the cache recovery policy. At present, mybatis provides the following policies.
        (1) LRU, the least recently used and the longest unused object
        (2) FIFO, first in, first out, removes objects in the order they enter the cache
        (3) Soft, soft reference, remove objects based on garbage collector state and soft reference rules
        (4) Weak reference, more active removal of objects based on garbage collector state and weak reference rules. LRU is used here,
                Remove the object that has not been used for the longest time

        Flush interval: refresh interval, in milliseconds. Here, 100 seconds of refresh is configured. If you do not configure it, then when
        The cache will be refreshed only when SQL is executed.

        Size: the number of references, a positive integer, represents the maximum number of objects that can be stored in the cache, and should not be set too large. Setting too much will cause memory overflow.
        1024 objects are configured here

        Readonly: read only means that the cache data can only be read but not modified. The advantage of this setting is that we can read the cache quickly, but the disadvantage is that we do not
        Method to modify the cache. Its default value is false and we are not allowed to modify it
    -->
    <cache eviction="LRU" flushInterval="100000" readOnly="true" size="1024"/>
    <resultMap id="studentMap" type="Student">
        <id property="id" column="id" />
        <result property="name" column="name" />
        <result property="age" column="age" />
        <result property="gender" column="gender" typeHandler="org.apache.ibatis.type.EnumOrdinalTypeHandler" />
    </resultMap>
    <resultMap id="collectionMap" type="Student" extends="studentMap">
        <collection property="teachers" ofType="Teacher">
            <id property="id" column="teach_id" />
            <result property="name" column="tname"/>
            <result property="gender" column="tgender" typeHandler="org.apache.ibatis.type.EnumOrdinalTypeHandler"/>
            <result property="subject" column="tsubject" typeHandler="org.apache.ibatis.type.EnumTypeHandler"/>
            <result property="degree" column="tdegree" javaType="string" jdbcType="VARCHAR"/>
        </collection>
    </resultMap>
    <select id="selectStudents" resultMap="collectionMap">
        SELECT
            s.id, s.name, s.gender, t.id teach_id, t.name tname, t.gender tgender, t.subject tsubject, t.degree tdegree
        FROM
            student s
        LEFT JOIN
            stu_teach_rel str
        ON
            s.id = str.stu_id
        LEFT JOIN
            teacher t
        ON
            t.id = str.teach_id
    </select>
    <! -- you can set usecache to specify whether the SQL is enabled for caching, true is on, false is off -- >
    <select id="selectAllStudents" resultMap="studentMap" useCache="true">
        SELECT id, name, age FROM student
    </select>
    <! -- refresh L2 cache
    <select id="selectAllStudents" resultMap="studentMap" flushCache="true">
        SELECT id, name, age FROM student
    </select>
    -->
</mapper>

3、 In mybatis- config.xml Enable Level 2 cache in

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <settings>
        <! -- this configuration enables the global mapper (L2 cache) to enable or disable caching -- >
        <setting name="cacheEnabled" value="true" />
        .....
    </settings>
    ....
</configuration>

4、 Testing

package com.yihaomen.service.student;

import com.yihaomen.mybatis.dao.StudentMapper;
import com.yihaomen.mybatis.model.Student;
import com.yihaomen.mybatis.model.Teacher;
import com.yihaomen.service.BaseTest;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import java.util.List;

/**
 *   
 *  @ProjectName: springmvc-mybatis 
 */
public class TestStudent extends BaseTest {

    public static void selectAllStudent() {
        SqlSessionFactory sqlSessionFactory = getSession();
        SqlSession session = sqlSessionFactory.openSession();
        StudentMapper mapper = session.getMapper(StudentMapper.class);
        List<Student> list = mapper.selectAllStudents();
        System.out.println(list);
        System.out.println (the "second execution");
        List<Student> list2 = mapper.selectAllStudents();
        System.out.println(list2);
        session.commit();
        System.out.println ("L2 cache observation point");
        SqlSession session2 = sqlSessionFactory.openSession();
        StudentMapper mapper2 = session2.getMapper(StudentMapper.class);
        List<Student> list3 = mapper2.selectAllStudents();
        System.out.println(list3);
        System.out.println (the "second execution");
        List<Student> list4 = mapper2.selectAllStudents();
        System.out.println(list4);
        session2.commit();

    }

    public static void main(String[] args) {
        selectAllStudent();
    }
}

result:

[QC] DEBUG [main] org.apache.ibatis.transaction.jdbc.JdbcTransaction.setDesiredAutoCommit(98) | Setting autocommit to false on JDBC Connection [[email protected]]
[QC] DEBUG [main] org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(139) | ==> Preparing: SELECT id, name, age FROM student
[QC] DEBUG [main] org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(139) | ==> Parameters:
[QC] DEBUG [main] org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(139) | <== Total: 6
Student {id =’1 ‘, name =’liu Dehua’, age = 55, gender = null, teachers = null}, student {id = 2 ‘, name =’zhang Huimei’, age = 49, gender = null, teachers = null}, student {id = 3 ‘, name =’tse Ting Ting Feng’, age = 35, gender = null, teachers = null}, student {id =’4 ‘, name =’fafei’, age = 47, gender = null, teachers = null}, student {id = 5 ‘, name =’name =’name =’35, age = 35, gender = null, teachers = null}, student {id =’4’, name =’fafafafei ‘, age = 47, gender = null, teachers = null, student {id = 5’, name =’name =’name =’student ‘, student Wang Feng‘, age = 48, gender = null, teachers = null}, Name = null, student = null, student = 36 ‘
Second execution
[QC] DEBUG [main] org.apache.ibatis.cache.decorators.LoggingCache.getObject(62) | Cache Hit Ratio [com.yihaomen.mybatis.dao.StudentMapper]: 0.0
Student {id =’1 ‘, name =’liu Dehua’, age = 55, gender = null, teachers = null}, student {id = 2 ‘, name =’zhang Huimei’, age = 49, gender = null, teachers = null}, student {id = 3 ‘, name =’tse Ting Ting Feng’, age = 35, gender = null, teachers = null}, student {id =’4 ‘, name =’fafei’, age = 47, gender = null, teachers = null}, student {id = 5 ‘, name =’name =’name =’35, age = 35, gender = null, teachers = null}, student {id =’4’, name =’fafafafei ‘, age = 47, gender = null, teachers = null, student {id = 5’, name =’name =’name =’student ‘, student Wang Feng’, age = 48, gender = null, teachers = null}, Name = null, student = null, student = 36 ‘
L2 cache observation point
[QC] DEBUG [main] org.apache.ibatis.cache.decorators.LoggingCache.getObject(62) | Cache Hit Ratio [com.yihaomen.mybatis.dao.StudentMapper]: 0.3333333333333333
Student {id =’1 ‘, name =’liu Dehua’, age = 55, gender = null, teachers = null}, student {id = 2 ‘, name =’zhang Huimei’, age = 49, gender = null, teachers = null}, student {id = 3 ‘, name =’tse Ting Ting Feng’, age = 35, gender = null, teachers = null}, student {id =’4 ‘, name =’fafei’, age = 47, gender = null, teachers = null}, student {id = 5 ‘, name =’name =’name =’35, age = 35, gender = null, teachers = null}, student {id =’4’, name =’fafafafei ‘, age = 47, gender = null, teachers = null, student {id = 5’, name =’name =’name =’student ‘, student Wang Feng’, age = 48, gender = null, teachers = null}, Name = null, student = null, student = 36 ‘
Second execution
[QC] DEBUG [main] org.apache.ibatis.cache.decorators.LoggingCache.getObject(62) | Cache Hit Ratio [com.yihaomen.mybatis.dao.StudentMapper]: 0.5
Student {id =’1 ‘, name =’liu Dehua’, age = 55, gender = null, teachers = null}, student {id = 2 ‘, name =’zhang Huimei’, age = 49, gender = null, teachers = null}, student {id = 3 ‘, name =’tse Ting Ting Feng’, age = 35, gender = null, teachers = null}, student {id =’4 ‘, name =’fafei’, age = 47, gender = null, teachers = null}, student {id = 5 ‘, name =’name =’name =’35, age = 35, gender = null, teachers = null}, student {id =’4’, name =’fafafafei ‘, age = 47, gender = null, teachers = null, student {id = 5’, name =’name =’name =’student ‘, student Wang Feng’, age = 48, gender = null, teachers = null}, Name = null, student = null, student = 36 ‘

Process finished with exit code 0

We can see from the results that SQL is executed only once, which proves that our level 2 cache is in effect.

https://gitee.com/huayicompany/springmvc-mybatis

Recommended Today

Summary of recent use of gin

Recently, a new project is developed by using gin. Some problems are encountered in the process. To sum up, as a note, I hope it can help you. Cross domain problems Middleware: func Cors() gin.HandlerFunc { return func(c *gin.Context) { //Here you can use * or the domain name you specify c.Header(“Access-Control-Allow-Origin”, “*”) //Allow header […]