This is the fourth day of my participation in the August More text Challenge. For details, see: August More Text Challenge


Related articles

MyBatis series summary: MyBatis series


preface

  • Shock!!! MyBaits has a cache? I don’t know it’s out of date
  • Although in our usual development will not use, but it is necessary to understand it!
  • In practice, the cache we use is usually Redis, interested students can go to the previous Redis series of articles, very hot oh ~ and has been completed!
  • Click the jump: Redis Series

1, level 1 cache

  • Mybatis turns on level 1 cache by default.

  • XML and mapper, so I’m not going to post the code here for the sake of space.

  • Let’s execute the query twice in a session, and see how many times it executes the SQL.

  • Junit Test

    •     @Test
          public void getMyBlog(a){
              SqlSession session = MybatisUtils.getSession();
              MyBlogMapper mapper = session.getMapper(MyBlogMapper.class);
              Map<String,Object> map = new HashMap<>();
              map.put("title"."Mybatis");
              // The 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();
          }
      
      Copy the code
  • The execution result

  • The result obviously tells us that in the same session scope, we perform the same operation, MyBatis will help us to store the data in the cache, the second query will preferentially query the data from the cache, and the SQL will be executed again only if the data cannot be found.

  • Of course, level 1 caching can be said to be valid only in queries. If any changes are made in the middle, the level 1 cache will be refreshed immediately.

  • Junit Test

    •     @Test
          public void getMyBlog(a){
              SqlSession session = MybatisUtils.getSession();
              MyBlogMapper mapper = session.getMapper(MyBlogMapper.class);
              Map<String,Object> map = new HashMap<>();
              map.put("title"."Mybatis");
              // The 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"."Rich woman asks me to go shopping with her 2");
              map1.put("autor"."Big big Big big");
      // map.put("reads","100000");
              Integer num = mapper.updateBlogName(map1);
              System.out.println("All updated:"+num+"Piece of data");
              session.commit();// Don't forget to commit transactions
              System.out.println("= = = = = = = = = = = = = = = = = = = = = = = =");
              // Second query
              List<Blog> myBlogMappers1 = mapper.getBlogInfo(map);
              for (Blog myBlogMapper : myBlogMappers1) {
                  System.out.println(myBlogMapper);
              }
              session.close();
          }
      Copy the code
  • The execution result

  • So to summarize level-1 cache

    • Level 1 cache is also called local cache.
    • All INSERT, Update, and DELETE statements in the mapping statement file refresh the cache.
    • To query different mapper.xml, caching is useless.
    • Manually clear the cache.
      • FlushCache: Set to true to flush the local cache and level-2 cache whenever a statement is called. The default value is true (for INSERT, UPDATE, and DELETE statements).
      • Execute the SQL twice, proving that the level 1 cache is invalid. Of course, only the current mapper select is invalid. The default value is false.

2, level 2 cache

  • The level 2 cache is also called the global cache. Scope is under the current mapper.

  • Enabling level-2 cache

    • Core profile

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

  • Junit Test

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

    •     @Test
          public void getMyBlog(a){
              SqlSession session = MybatisUtils.getSession();
              MyBlogMapper mapper = session.getMapper(MyBlogMapper.class);
              Map<String,Object> map = new HashMap<>();
              map.put("title"."Mybatis");
              // The first query
              List<Blog> myBlogMappers = mapper.getBlogInfo(map);
              for (Blog myBlogMapper : myBlogMappers) {
                  System.out.println(myBlogMapper);
              }
              session.commit();// If the transaction is committed, it will be stored in 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();
          }
      Copy the code
    • Of course, at this point the normal entity class is useless and needs to be serialized.

    • The following error message is displayed

    • @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;
      }
      Copy the code
  • Execute and see the result

  • Parameters that

    • <cache eviction="FIFO"
             flushInterval="60000"
             size="512"
             readOnly="true"/>
      Copy the code
    • Eviction: Reclaim strategy for cache

      • LRU – Least recently used, removes objects that have not been used for the longest time.
      • FIFO – First in, first out, removes objects in the order they entered the cache.
      • SOFT – SOFT references that remove objects based on garbage collector state and SOFT reference rules.
      • WEAK – WEAK references, more aggressive removal of objects based on garbage collector and WEAK reference rules.
    • FlushInterval: specifies how often the cache is flushed in milliseconds. The default value is not flushInterval.

    • Size: How many elements are in the cache.

    • ReadOnly: Read-only or not.

      • True: read only: Mybatis assumes that all operations to retrieve data from the cache are read only and will not modify the data.
      • In order to speed up data acquisition, MyBatis will directly give the user a reference to the data in the cache. It’s not safe. It’s fast.
      • False: read/write (default) : Mybatis thinks the obtained data may be modified.
      • Mybatis will clone a new data to you using serialization & deserialization technology. Safe, relatively slow.
  • conclusion

    • Level 2 cache enabled, valid under Mapper.
    • All data will be stored in level 1 cache first.
    • Only commits to the level 2 cache when the reply is committed, or when it is closed.

Custom cache

  • Similarly, in addition to the first and second level caches provided by MyBatis, we can also customize the caches.

  • The introduction of pom

    • <! -- 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>
      Copy the code
  • 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: cache path. Ehcache is divided into memory and disk levels. This property defines the cache location of the disk. The parameters are described as follows: user.home - user home directory user.dir - User current working directory java.io.tmpdir - Default path to temporary files -> <diskStore path="java.io.tmpdir/Tmp_EhCache"/ > <! -- defaultCache: the defaultCache policy that is used when ehcache cannot find the defined cache. Only one can be defined. -- > <! -- name: indicates the cache name. MaxElementsInMemory: indicates the maximum number of cached disks. MaxElementsOnDisk: indicates the maximum number of cached disks. Eternal: whether the object is permanent, once set, timeout will have no effect. OverflowToDisk: specifies whether to save to disk when the system is down. TimeToIdleSeconds: Specifies the allowed idle time (in seconds) for an object before it becomes invalid. Only when the eternal =falseAn optional property when the object is not permanent. The default value is0Which means infinite idle time. TimeToLiveSeconds: Sets the amount of time (in seconds) an object can live before it expires. The maximum time is between the creation time and the expiration time. Only when the eternal =falseUsed when the object is not permanent. The default is0.That is, the lifetime of the object is infinite. DiskPersistent: Indicates Whether to cache the vm restart data Whether the disk store countdown between restarts of the Virtual Machine. Thedefault value is false.diskspoolBufferSizEMb: This parameter sets the cache size of the DiskStore (disk cache). The default is 30MB. Each Cache should have its own buffer. DiskExpiryThreadIntervalSeconds: disk failure thread running time interval, by default120Seconds. MemoryStoreEvictionPolicy: when maxElementsInMemory limit is reached, Ehcache will be based on the specified strategies to clear the memory. The default policy is LRU (least recently used). You can set it to FIFO (first in, first out) or LFU (less used). ClearOnFlush: specifies whether to flush the memory when the memory quantity reaches the maximum. MemoryStoreEvictionPolicy: optional strategies are: the LRU (least recently used, the default policy), FIFO (first in first out), LFU (at least) visited. FIFO, first in first out. LFU, Less Frequently Used, is the strategy Used in the example above, which is the least Frequently Used. As mentioned above, cached elements have a hit attribute, and the one with the lowest hit value will be cleared out of the cache. LRU, Least Recently Used, the cached element has a timestamp. When the cache is full and needs to make room for new elements, the element whose timestamp is furthest from the current time will be cleared from 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>
      Copy the code
    • Errors may be reported

      • The solution is as follows
  • Class that implements Catch

    • /** * Class that implements 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(a){        System.out.println("Initialize -1!");    }  Public BatisCache(String ID){system.out.println (" initialize -2! "); ); this.id = id; } public String getId() {system.out.println (" getId: "+ ID); return id; } public int getSize() {system.out.println (" getSize! "); ); return 0; } public void putObject(Object key, Object value) {system.out.println (" add element to cache: key=" + key+",value=" + value); cache.put(key,value); } public Object getObject(Object KEY) {system.out.println (" getvalue by KEY: "+ KEY); System.out.println("OVER"); System.out.println("======================================================="); System.out.println(" value: "+ cache.get(key)); System.out.println("=====================OVER=============================="); return cache.get(key); } public Object removeObject(Object key) {system.out.println (" remove cache Object: "+ key); return null; Public void clear() {system.out.println (" Clear cache! "); ); cache.clear(); } public ReadWriteLock getReadWriteLock() {system.out.println (" Get the lock!! "); ); return lock; }}
      Copy the code
  • Junit Test

    •     @Test    public void TestCache(a){        SqlSession session = MybatisUtils.getSession();        MyBlogMapper mapper = session.getMapper(MyBlogMapper.class);        Map<String,Object> map = new HashMap<>();        map.put("title"."Mybatis");        MyBlogMappers = mapper.getBlogInfo(map); for (Blog myBlogMapper : myBlogMappers) { System.out.println(myBlogMapper); } List
                
                  myBlogMappers1 = mapper.getBlogInfo(map); for (Blog myBlogMapper : myBlogMappers1) { System.out.println(myBlogMapper); } // If we use second-level caching, we need to commit the transaction session.com MIT (); System.out.println("============================================================="); SqlSession session1 = myBatiSutils.getSession (); MyBlogMapper mapper1 = session1.getMapper(MyBlogMapper.class); List
                 
                   myBlogMappers2 = mapper.getBlogInfo(map); session1.commit(); }
                 
      Copy the code
  • The execution result

  • conclusion

    • So in myBatis’ default cache, the cache ID is the namespace namespace.
    • The data type is map, key is namespace+ SQL statement, etc., and value is the data queried by SQL statement.

Four, finish the conclusion

  • This concludes the MyBatis series. The basics are pretty much done.
  • Below you can see I wrote Spring series, has been completed, and very detailed oh ~
  • Click to jump to the Spring series summary
  • Next I will not regularly update MyBatis source code article, is also put in this column, I hope you can point to a focus on a little like!
  • Thanks for your support!

I see no ending, but I will search high and low

If you think I blogger writes good! Writing is not easy, please like, follow, comment to encourage the blogger ~hahah