MyBatis notes cache

Cache introduction

1. What is Cache?

  • There is temporary data in memory.
  • Put the data that users often query in the cache (memory), users do not need to query the data from the disk (relational database data file), query from the cache, so as to improve the query efficiency and solve the performance problem of high concurrency system.

2. Why cache?

  • Reduce the number of interactions with the database, reduce system overhead, and improve system efficiency.

3. What kind of data can be cached?

  • Data that is frequently queried and not frequently changed.

Mybatis cache

  • MyBatis includes a very powerful query caching feature that makes it very easy to customize and configure the cache. Caching can greatly improve query efficiency.

  • In MyBatis system, two levels of cache are defined by default: first level cache and second level cache

    1. By default, only the first level cache is enabled. (SqlSession level cache, also known as local cache)
    2. The second level cache needs to be opened and configured manually. It is based on the namespace level cache.
    3. To improve the scalability, MyBatis defines the Cache interface Cache. We can define the second level Cache by implementing the Cache interface

First level cache

  • First level cache is also called local cache:

    • The data queried during the same session as the database is placed in the local cache.
    • In the future, if you need to obtain the same data, you can take it directly from the cache, without having to query the database again;

test
1. Add logs to mybatis to facilitate test results
2. interface

//Query users by id
User queryUserById(@Param("id") int id);

3. Mapper file corresponding to the interface

<select id="queryUserById" resultType="user">
    select * from user where id = #{id}
</select>

4. test

@Test
    public void test1(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> users = mapper.queryUsersById(1);
        System.out.println(users);
        List<User> user2 = mapper.queryUsersById(1);
        System.out.println(user2);
        System.out.println(users==user2);

        sqlSession.close();
    }

5. Result analysis

Four cases of L1 cache failure

  • The first level cache is the SqlSession level cache, which is always on. We can't close it;
  • Invalidation of level-1 cache: the current level-1 cache is not used. The effect is that another query request needs to be initiated to the database!
    • sqlSession is different
@Test
    public void test2(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        SqlSession sqlSession2 = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
        List<User> users = mapper.queryUsersById(1);
        System.out.println(users);
        List<User> user2 = mapper2.queryUsersById(1);
        System.out.println(user2);
        System.out.println(users==user2);

        sqlSession.close();
        sqlSession2.close();
    }

Result

Conclusion: the cache in each sqlSession is independent of each other

  • Same sqlSession, different query conditions
@Test
public void testQueryUserById(){
    SqlSession session = MybatisUtils.getSession();
    UserMapper mapper = session.getMapper(UserMapper.class);
    UserMapper mapper2 = session.getMapper(UserMapper.class);

    User user = mapper.queryUserById(1);
    System.out.println(user);
    User user2 = mapper2.queryUserById(2);
    System.out.println(user2);
    System.out.println(user==user2);

    session.close();
}

Result: two SQL statements were sent,
Conclusion: this data does not exist in the current cache

SqlSession is the same. Add, delete and modify operations are performed between queries

1. plus method

//Modify user
int updateUser(Map map);

2. writing sql

<update id="updateUser" parameterType="map">
    update user set name = #{name} where id = #{id}
</update>

3. test

@Test
public void testQueryUserById(){
    SqlSession session = MybatisUtils.getSession();
    UserMapper mapper = session.getMapper(UserMapper.class);

    User user = mapper.queryUserById(1);
    System.out.println(user);

    HashMap map = new HashMap();
    map.put("name","jay");
    map.put("id",4);
    mapper.updateUser(map);

    User user2 = mapper.queryUserById(1);
    System.out.println(user2);

    System.out.println(user==user2);

    session.close();
}

Results: the query was re executed after adding, deleting and modifying in the middle. Conclusion: the addition, deletion and modification may affect the current data

The sqlSession is the same, clear the first level cache manually

@Test
public void testQueryUserById(){
    SqlSession session = MybatisUtils.getSession();
    UserMapper mapper = session.getMapper(UserMapper.class);

    User user = mapper.queryUserById(1);
    System.out.println(user);

    session.clearCache();//Clear cache manually

    User user2 = mapper.queryUserById(1);
    System.out.println(user2);

    System.out.println(user==user2);

    session.close();
}

So, the first level cache is a map

Two level cache

  • The second level cache is also called global cache. The scope of the first level cache is too low, so the second level cache is born

  • Based on the namespace level cache, a namespace corresponds to a secondary cache;

  • Working mechanism

    • When a session queries a piece of data, the data will be placed in the first level cache of the current session;
    • If the current session is closed, the first level cache corresponding to the session will be lost; but what we want is that the session is closed, and the data in the first level cache will be saved to the second level cache;
    • The new session query information can get the content from the two level cache;
    • The data detected by different mapper s will be put in their own corresponding cache (map);

Use
Official documents
1. Enable global cache [mybatis-config.xml]

<setting name="cacheEnabled" value="true"/>

2. Remove the configuration in each mapper.xml to use the secondary cache.

<cache/>

Official example =====> view official documents
<cache
  eviction="FIFO"
  flushInterval="60000"
  size="512"
  readOnly="true"/>
This more advanced configuration creates a FIFO cache, which is refreshed every 60 seconds. It can store up to 512 references of the result object or list, and the returned objects are considered read-only, so modifying them may cause conflicts among callers in different threads.

3. test

  • All entity classes implement the serialization interface first
  • Test code
@Test
public void testQueryUserById(){
    SqlSession session = MybatisUtils.getSession();
    SqlSession session2 = MybatisUtils.getSession();

    UserMapper mapper = session.getMapper(UserMapper.class);
    UserMapper mapper2 = session2.getMapper(UserMapper.class);

    User user = mapper.queryUserById(1);
    System.out.println(user);
    session.close();

    User user2 = mapper2.queryUserById(1);
    System.out.println(user2);
    System.out.println(user==user2);

    session2.close();
}

conclusion

  • As long as the second level cache is enabled, our queries in the same Mapper can get data in the second level cache
  • The data found will be put in the first level cache by default
  • Only after the session is submitted or closed, the data in the L1 cache will be transferred to the L2 cache

Cache principle

EhCache

Third party cache implementation - EhCache: Baidu Encyclopedia
Official documents

  • Ehcache is a widely used java distributed cache, which is used for general cache;
  • To use Ehcache in your application, you need to introduce dependent jar packages
<!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache -->
<dependency>
    <groupId>org.mybatis.caches</groupId>
    <artifactId>mybatis-ehcache</artifactId>
    <version>1.1.0</version>
</dependency>
  • Use the corresponding cache in mapper.xml
<mapper namespace = "org.acme.FooMapper" > 
    <cache type = "org.mybatis.caches.ehcache.EhcacheCache" /> 
</mapper>
  • Write ehcache.xml file, if the / ehcache.xml resource is not found or there is a problem when loading, the default configuration will be used.
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         updateCheck="false">
    <!--
       diskStore: Is the cache path, ehcache There are two levels: memory and disk. This attribute defines the cache location of the disk. The parameters are explained as follows:
       user.home – User home directory
       user.dir  – User's current working directory
       java.io.tmpdir – Default temporary file path
     -->
    <diskStore path="./tmpdir/Tmp_EhCache"/>
    
    <defaultCache
            eternal="false"
            maxElementsInMemory="10000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="259200"
            memoryStoreEvictionPolicy="LRU"/>
 
    <cache
            name="cloud_user"
            eternal="false"
            maxElementsInMemory="5000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="1800"
            memoryStoreEvictionPolicy="LRU"/>
    <!--
       defaultCache: Default cache policy, when ehcache This caching policy is used when the defined cache cannot be found. Only one can be defined.
     -->
    <!--
      name:Cache name.
      maxElementsInMemory:Maximum number of cache
      maxElementsOnDisk: Maximum number of hard disk cache.
      eternal:Whether the object is permanently valid, once it is set, timeout It will not work.
      overflowToDisk:Save to disk or not, when the system crashes
      timeToIdleSeconds:Sets the allowed idle time (in seconds) of the object before expiration. Only when eternal=false Used when the object is not permanently valid. Optional property. The default value is0,That is to say, the idle time is infinite.
      timeToLiveSeconds:Sets the time (in seconds) that an object is allowed to live before it expires. The maximum time is between creation time and expiration time. Only when eternal=false Used when the object is not permanently valid, the default is0.,That is, the life time of the object is infinite.
      diskPersistent: Whether to cache virtual machine restart data Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
      diskSpoolBufferSizeMB: This parameter setting DiskStore(Disk cache). The default is30MB. each Cache Each should have its own buffer.
      diskExpiryThreadIntervalSeconds: Disk failure thread run time interval, default is120Seconds.
      memoryStoreEvictionPolicy: When reach maxElementsInMemory When limiting, Ehcache The memory will be cleaned according to the specified policy. The default policy is LRU(Least recently used). You can set to FIFO(First in, first out) or LFU(Less use).
      clearOnFlush: Whether to clear when the memory quantity is the maximum.
      memoryStoreEvictionPolicy:The optional strategies are: LRU(Least recently used, default policy) FIFO(First in, first out) LFU(Minimum number of visits).
      FIFO,first in first out,This is the most familiar one, first in, first out.
      LFU, Less Frequently Used,This is the strategy used in the above example. To be frank, it is the one that has been used least for a long time. As mentioned above, the cached element has a hit Attribute, hit The lowest value will be flushed out of the cache.
      LRU,Least Recently Used,The most recently used, cached elements have a timestamp. When the cache capacity is full and there is a need to make room to cache new elements, the elements with the farthest timestamp from the current time in the existing cache elements will be cleared out of the cache.
   -->

</ehcache>
35 original articles published, praised 0, 466 visitors
Private letter follow

Tags: Session Ehcache Mybatis xml

Posted on Sun, 15 Mar 2020 03:21:42 -0400 by hagman