MyBatis cache | MyBatis series

Related articles

MyBatis collection summary: MyBatis series

preface

  • Shock! MyBaits has a cache? I don't know. It's out of date~
  • Although we usually do not use it in development, it is necessary to understand it!
  • In actual work, the cache we use is usually Redis. Interested students can go to see the series of Redis articles I wrote earlier. It's very hot ~ and it's over!
  • Click jump: Redis series

1, L1 cache

  • In fact, Mybatis is enabled by default. We can test it.

  • Just write one of xml and mapper. In order to omit space, I won't post code here.

  • We execute the query statement twice in a session to see how many times it will execute sql.

  • Junit Test

    •     @Test
          public void getMyBlog(){
              SqlSession session = MybatisUtils.getSession();
              MyBlogMapper mapper = session.getMapper(MyBlogMapper.class);
              Map<String,Object> map = new HashMap<>();
              map.put("title","Mybatis");
              //First query
              List<Blog> myBlogMappers = mapper.getBlogInfo(map);
              for (Blog myBlogMapper : myBlogMappers) {
                  System.out.println(myBlogMapper);
              }
              System.out.println("========================");
              //Second query
              List<Blog> myBlogMappers1 = mapper.getBlogInfo(map);
              for (Blog myBlogMapper : myBlogMappers1) {
                  System.out.println(myBlogMapper);
              }
              session.close();
          }
      
      
  • results of enforcement

  • The results clearly tell us that under the same session scope, we perform the same operations. MyBatis will help us store the data in the cache. The second query will give priority to querying the data from the cache. If we can't find it, we will execute sql again.

  • Of course, L1 caching can be said to be effective only in queries. If there are additions, deletions and changes in the middle, the L1 cache will be refreshed immediately.

  • Junit Test

    •     @Test
          public void getMyBlog(){
              SqlSession session = MybatisUtils.getSession();
              MyBlogMapper mapper = session.getMapper(MyBlogMapper.class);
              Map<String,Object> map = new HashMap<>();
              map.put("title","Mybatis");
              //First query
              List<Blog> myBlogMappers = mapper.getBlogInfo(map);
              for (Blog myBlogMapper : myBlogMappers) {
                  System.out.println(myBlogMapper);
              }
              System.out.println("=========================");
              Map<String,Object> map1 = new HashMap<>();
              map1.put("id","3");
              map1.put("title","The rich woman asked me to go shopping with her 2");
              map1.put("autor","Big big fish");
      //        map.put("reads","100000");
              Integer num = mapper.updateBlogName(map1);
              System.out.println("Total updates:"+num+"Data bar");
              session.commit();//Update don't forget to commit the transaction
              System.out.println("========================");
              //Second query
              List<Blog> myBlogMappers1 = mapper.getBlogInfo(map);
              for (Blog myBlogMapper : myBlogMappers1) {
                  System.out.println(myBlogMapper);
              }
              session.close();
          }
      
  • results of enforcement

  • To summarize, L1 cache

    • The first level cache is also called local cache.
    • All insert, update, and delete statements in the mapping statement file flush the cache.
    • Query different mappers XML, caching is useless.
    • Manually clear the cache.
      • flushCache: after setting it to true, as long as the statement is called, the local cache and L2 cache will be emptied. The default value is (for insert, update and delete statements) true.
      • The sql is executed twice to prove that the L1 cache is invalid. Of course, only the current mapper's select is invalid, and the default value is false.

2, L2 cache

  • L2 cache is also called global cache. The scope is under the current mapper.

  • Enable L2 cache

    • Core profile

    •     <settings>
              <setting name="logImpl" value="LOG4J"/>
              <setting name="cacheEnabled" value="true"/>
          </settings>
      
    • xml

  • Junit Test

    • We open two session s to prove that there are currently two local scopes

    •     @Test
          public void getMyBlog(){
              SqlSession session = MybatisUtils.getSession();
              MyBlogMapper mapper = session.getMapper(MyBlogMapper.class);
              Map<String,Object> map = new HashMap<>();
              map.put("title","Mybatis");
              //First query
              List<Blog> myBlogMappers = mapper.getBlogInfo(map);
              for (Blog myBlogMapper : myBlogMappers) {
                  System.out.println(myBlogMapper);
              }
              session.commit();//The transaction needs to be committed here. Otherwise, the cache is still a level-1 cache. After the transaction is committed, it will be saved to the global cache
              System.out.println("========================");
              SqlSession session1 = MybatisUtils.getSession();
              MyBlogMapper mapper1 = session1.getMapper(MyBlogMapper.class);
              //Second query
              List<Blog> myBlogMappers1 = mapper1.getBlogInfo(map);
              for (Blog myBlogMapper : myBlogMappers1) {
                  System.out.println(myBlogMapper);
              }
              session.close();
          }
      
    • Of course, at this time, ordinary entity classes are useless and need to be serialized.

    • The error information is as follows

    • @Data
      @AllArgsConstructor
      @NoArgsConstructor
      @Alias("Blog")
      public class Blog  implements Serializable{
          private Integer id;
          private String title;
          private String autor;
          private Date creat_time;
          private Integer reads;
      }
      
  • Execution depends on the result

  • Parameter description

    • <cache eviction="FIFO"
             flushInterval="60000"
             size="512"
             readOnly="true"/>
      
    • eviction: cache recycling policy

      • LRU - least recently used, removing objects that have not been used for the longest time.
      • FIFO - first in first out, removing objects in the order they enter the cache.
      • SOFT - SOFT reference to remove objects based on garbage collector status and SOFT reference rules.
      • WEAK - WEAK references, more actively removing objects based on garbage collector and WEAK reference rules.
    • Flush interval: cache refresh interval. How often the cache is emptied. It is not emptied by default. Set a millisecond value.

    • size: how many elements are stored in the cache.

    • readOnly: whether to read only.

      • true: read only: mybatis believes that all operations to obtain data from the cache are read-only operations and will not modify the data.
      • In order to speed up the acquisition of data, mybatis will directly give the reference of data in the cache to the user. Unsafe, fast.
      • false: read / write (default): mybatis thinks the acquired data may be modified.
      • mybatis will clone a new piece of data to you by using the technology of serialization and deserialization. Safe, relatively slow.
  • summary

    • The L2 cache is enabled, which is valid under Mapper.
    • All data will be put in the first level cache first.
    • Only when the reply is submitted or closed will it be submitted to the L2 cache.

3, Custom cache

  • Similarly, in addition to the primary and secondary caches provided by MyBatis, we can also customize the cache.

  • pom introduction

    •     <!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache -->
          <dependency>
              <groupId>org.mybatis.caches</groupId>
              <artifactId>mybatis-ehcache</artifactId>
              <version>1.2.0</version>
          </dependency>
      
  • ehcache.xml

    • <?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="java.io.tmpdir/Tmp_EhCache"/>
          <!--
             defaultCache: Default cache policy, when ehcache This cache policy is used when the defined cache cannot be found. Only one can be defined.
           -->
          <!--
            name:Cache name.
            maxElementsInMemory:Maximum number of caches
            maxElementsOnDisk: Maximum number of hard disk caches.
            eternal:Whether the object is permanently valid, but once it is set, timeout Will not work.
            overflowToDisk:Whether to save to disk when the system crashes
            timeToIdleSeconds:Set the allowed idle time of the object before expiration (unit: seconds). Only if eternal=false It is used when the object is not permanently valid. It is an optional attribute. The default value is 0, that is, the idle time is infinite.
            timeToLiveSeconds:Set the allowable survival time of the object before invalidation (unit: seconds). The maximum time is between creation time and expiration time. Only if eternal=false Used when the object is not permanently valid. The default is 0.,That is, the survival 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(Cache size of disk cache). The default is 30 MB. each Cache Each should have its own buffer.
            diskExpiryThreadIntervalSeconds: The running time interval of disk failure thread is 120 seconds by default.
            memoryStoreEvictionPolicy: When reached maxElementsInMemory When restricted, Ehcache The memory will be cleaned up according to the specified policy. The default policy is LRU(Least recently used). You can set it to FIFO(First in first out) or LFU(Less used).
            clearOnFlush: Whether to clear when the amount of memory is 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, first in, first out.
            LFU, Less Frequently Used,This is the strategy used in the above example. To put it bluntly, it has always been the least used. As mentioned above, the cached element has a hit Properties, hit The smallest value will be flushed out of the cache.
            LRU,Least Recently Used,The least recently used element in the cache has a timestamp. When the cache capacity is full and it needs to make room for caching new elements, the element with the farthest timestamp from the current time in the existing cache elements will be cleared out of the cache.
         -->
          <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"/>
      
      </ehcache>
      
    • Errors may be reported

      • The solution is as follows
  • Class implementing Catch

    • /** * Class implementing cache * @ author dingyongjun * @ date 2021 / 08 / 01 * @ return map < string, Object > */public class BatisCache implements Cache {    private ReadWriteLock lock = new ReentrantReadWriteLock();    private ConcurrentHashMap<Object,Object> cache = new ConcurrentHashMap<Object, Object>();    private String id;    public  BatisCache(){        System.out.println("initialization-1!");    }  //The constructor must be public batiscache (string ID) {system.out.println ("initialization - 2!"); this.id = id;    }    //  Get cache number public string getid() {system. Out. Println ("get ID:" + ID); return ID;}// Get the size of the cache object public int getsize() {system. Out. Println ("get cache size!"); return 0;    }    //  Save key value cache object public void putobject (object key, object value) {system.out.println ("add elements to cache: key =" + key + ", value =" + value); cache.put (key, value);}// Through key public object GetObject (object key) {system.out.println ("get value via key:" + key)); system.out.println ("over"); system.out.println ("system ==================================================================================================================( "=====================OVER==============================");         return cache. get(key);    }    //  Delete the cache object public object removeobject (object key) {system.out.println ("remove cache object:" + key); return null;}// Clear cache public void clear() {system. Out. Println ("clear cache!"); cache.clear();    }    //  Get the cache read-write lock public readwritelock getreadwritelock() {system. Out. Println ("get lock object!!!"); return lock;    }}
      
  • Junit Test

    •     @Test    public void TestCache(){        SqlSession session = MybatisUtils.getSession();        MyBlogMapper mapper = session.getMapper(MyBlogMapper.class);        Map<String,Object> map = new HashMap<>();        map.put("title","Mybatis");        //First query list < blog > myblogmappers = mapper getBlogInfo(map);         for (Blog myBlogMapper : myBlogMappers) {            System.out.println(myBlogMapper);        }        // The second query list < blog > myblogmappers1 = mapper getBlogInfo(map);         for (Blog myBlogMapper : myBlogMappers1) {            System.out.println(myBlogMapper);        }        // If we use L2 cache, we need to commit the transaction session commit();         System. out. println("=============================================================");        // Get new session sqlsession session1 = mybatisutils getSession();         MyBlogMapper mapper1 = session1. getMapper(MyBlogMapper.class);         List<Blog> myBlogMappers2 = mapper. getBlogInfo(map);         session1. commit();    }
      
  • results of enforcement

  • summary

    • Therefore, in the default cache of mybatis, the id value of the cache is the namespace namespace.
    • The data type is map type, key is namespace+sql statement, etc., and value is the data queried by SQL statement.

4, Concluding remarks

  • This concludes the MyBatis series. The basic things have basically been written.
  • Now you can see the Spring series I wrote. It is over and very detailed~
  • Click jump Spring series summary
  • Next, I will update the source code article of MyBatis from time to time, which is also placed in this column. I hope you can pay attention and praise!
  • Thank you for your support!

It's a long way to go. I'm going to ask for it from top to bottom~

If you think i blogger writes well! Writing is not easy. Please praise, pay attention and comment to give the blogger an encouragement ~hahah

Keywords: Java Mybatis

Added by echox on Thu, 10 Mar 2022 03:11:13 +0200