Mybatis L1 and L2 cache

Time:2020-6-4

Mybatis L1 and L2 cache

What is cache?

Cache is the buffer of data exchange, which is the temporary data in memory.

So why do we use caching?

For example, every time we query user information, we need to request the database every time, and the database will compile and execute your SQL statement, so the efficiency will be very low.For frequent access to data that does not change frequently, and the amount of data is large, usually, add it to the cache, and judge before fetching each time. If the cache is not empty, then take the value from the cache. If it is empty, then request the database and add the data to the cache.

Cachedobjectivenamely:Reduce the number of interactions with the database and improve the efficiency of execution.

Now that we know about the concept of caching, let’s talk about caching in mybatis! Next, we will introduce the first level cache and the second level cache in mybatis.

First, let’s put out the directory structure
Mybatis L1 and L2 cache

Userdao interface

public interface UserDao {
    /**
     *Query user information according to ID
     */

    User findById(Integer id);

}

User class (entity class)

public class User implements Serializable {
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;

    public User() {
    }

    For code space, getter and setter methods are omitted here
}

Mybatis main profile SqlMapConfig.xml

<?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">
<! -- MySQL main configuration file -- >

    <configuration>

    <! -- enable L2 cache -- >
    <settings>
        <setting name="cacheEnabled" value="true"/>
    </settings>



    <! -- configure to use aliases, which will scan the classes in the package. The aliases are class names (both uppercase and lowercase are OK) - >
    <typeAliases>
        <package name="com.wanghao.domain"/>
    </typeAliases>

    <environments default="mysql">
        <! -- configure MySQL environment -- >
        <environment id="mysql">
            <! -- configure transaction type -- >
            <transactionManager type="JDBC"></transactionManager>
           <! -- configure data source -- >
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/eesy?serverTimezone=UTC"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <! -- specifies the location of the mapping file, which refers to the independent configuration file of each Dao -- >
    <mappers>

        <package name="com.wanghao.dao"/>
    </mappers>
    </configuration>

UserDao.xml (Dao map 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">

<! -- the namespace property is the fully qualified class name of the corresponding Dao interface -- >
<mapper namespace="com.wanghao.dao.UserDao">
        <! -- start supporting L2 cache -- >
    <cache/>
    <select id="findById" parameterType="int" resultType="user" useCache="true">
        select * from user where id = #{uid}
    </select>

</mapper>

First level cache: the cache of sqlsession object in mybatis

When we execute the query, the results of the query will be stored in a block of sqlsession at the same time. When we query the same data again, mybatis will first go to sqlsession to check whether there is any, and in some cases, it will directly use it without requesting the database again.

Test L1 cache

The first level cache is the cache of sqlsession scope. When calling the modify, add, delete, commit(), close(), clearcache() of sqlsession
By querying the same ID twice, it can be seen whether the query statement is executed again the second time to indicate whether the first level cache is used. It can also be explained by whether it is the same object twice.

public class FirstLevelCacheTest {
    InputStream in;
    SqlSessionFactoryBuilder builder;
    SqlSessionFactory factory;
    SqlSession session;
    UserDao userDao;
    /**
     *The before annotation will be executed before the test method is executed
     * @throws Exception
     */

    @Before
    public void init() throws Exception{
        //1. Read configuration file
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2. Create sqlsessionfactory factory
        builder = new SqlSessionFactoryBuilder();
        factory = builder.build(in);
        //3. Use factory to produce sqlsession object
        session = factory.openSession();
        //4. Use sqlsession to create Dao interface proxy object
        userDao = session.getMapper(UserDao.class);
    }

    /**
     *After annotation will be executed after the test method is executed
     * @throws Exception
     */
    @After
    public void destroy()throws Exception{

        //Commit transaction
        session.commit();

        //6. Release resources
        session.close();
        in.close();

    }

    @Test
    public void testCache(){

        User user1 = userDao.findById(45);
        System.out.println(user1);
        
            //Clear cache
           //session.clearCache();
        
        User user2 = userDao.findById(45);
        System.out.println(user2);
       //By comparing whether two times is the same object
        System.out.println(user1==user2);


    }

}

result:
Mybatis L1 and L2 cache
Mybatis L1 and L2 cache

When we put session.clearCache (); the comment of this sentence is opened, which means that the sqlsession object cache is cleaned, that is, the first level cache is cleaned. We will find that the second query will request the database again.
Mybatis L1 and L2 cache

Second level cache: the cache of sqlsessionfactory objects in mybatis. Sqlsession objects created by the same sqlsessionfactory share the cache

Additional configuration is required to use mybatis’s L2 cache

  • Configure in the mybatis main configuration file, that is, the SqlMapConfig.xml
<! -- enable L2 cache -- >
    <settings>
        <setting name="cacheEnabled" value="true"/>
    </settings>
  • Configure < cache / > in the map file of Dao and usecache = “true” in the select tab, that is UserDao.xml
<?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">

<! -- the namespace property is the fully qualified class name of the corresponding Dao interface -- >
<mapper namespace="com.wanghao.dao.UserDao">
       
    <! -- start supporting L2 cache -- >
    <cache/>
    
    <select id="findById" parameterType="int" resultType="user" useCache="true">
        <! -- don't forget to add usecache = "true" -- >
        select * from user where id = #{uid}
    
    </select>

</mapper>

Test L2 cache

Through two sqlsession tests created by the same sqlsessionfactory object,

After executing the query operation with sqlsession1, we call sqlsession1.close(), close the first level cache, and query again with sqlsession2 for the second time, because the first level cache has been closed, and different sqlsession objects are used. If the second query result is not executed with SQL statement, it indicates that the second level cache is effective!

public class SecondLevelCacheTest {
    InputStream in;
    SqlSessionFactoryBuilder builder;
    SqlSessionFactory factory;

    /**
     *The before annotation will be executed before the test method is executed
     * @throws Exception
     */

    @Before
    public void init() throws Exception{
        //1. Read configuration file
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2. Create sqlsessionfactory factory
        builder = new SqlSessionFactoryBuilder();
        factory = builder.build(in);
        //3. Use factory to produce sqlsession object

    }

    /**
     *After annotation will be executed after the test method is executed
     * @throws Exception
     */
    @After
    public void destroy()throws Exception{


        in.close();

    }

    @Test
    public void testCache(){
        
        SqlSession sqlSession1 = factory.openSession();
        UserDao dao1 = sqlSession1.getMapper(UserDao.class);
        User user1 = dao1.findById(45);
       
        sqlSession1.close();

        SqlSession sqlSession2 = factory.openSession();
        UserDao dao2 = sqlSession2.getMapper(UserDao.class);
        User user2 = dao2.findById(45);
        sqlSession2.close();
       


    }

}

 ​

Mybatis L1 and L2 cache
be careful:When we use L2 caching, the cached classes must implement java.io.Serializable Interface, which can use serialization to save objects.