Mybatis lazy loading (caching)

Lazy loading

  • Advantages of step-by-step query: Lazy loading can be achieved, but global configuration information must be set in the core configuration file:
  • lazyLoadingEnabled: global switch for lazy loading. When enabled, all associated objects will be loaded lazily
    • aggressiveLazyLoading: When turned on, any method call will load all properties of the object. Otherwise, each property is loaded on demand
  • At this time, on-demand loading can be achieved. Whatever data is obtained, only the corresponding SQL will be executed. At this time, you can set whether the current step-by-step query uses lazy loading through the fetchType attribute in association and collection, fetchType=”lazy (lazy loading) | eager (immediate loading)”
<settings>
<!--Enable lazy loading-->
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
@Test
public void getEmpAndDeptByStepOne() {<!-- -->
'''
Get mapper
'''
mapper.getEmpAndDeptByStepOne(1);
System.out.println(emp.getEmpName());
}

Turn off lazy loading and both SQL statements are run.

Turn on lazy loading and only run the SQL statement to obtain emp

@Test
public void getEmpAndDeptByStepOne() {<!-- -->
'''
Get mapper
'''
Emp emp = mapper.getEmpAndDeptByStepOne(1);
System.out.println(emp.getEmpName());
System.out.println("----------------");
System.out.println(emp.getDept());
}

After it is turned on, the corresponding SQL statement will be called only when querying dept.

fetchType: When global lazy loading is enabled, you can manually control the effect of lazy loading through this attribute, fetchType=”lazy (lazy loading)|eager (immediate loading)”

<resultMap id="empAndDeptByStepResultMap" type="Emp">
<id property="eid" column="eid"></id>
<result property="empName" column="emp_name"></result>
<result property="age" column="age"></result>
<result property="sex" column="sex"></result>
<result property="email" column="email"></result>
<association property="dept"
select="com.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo"
column="did"
fetchType="lazy"></association>
</resultMap>

MyBatis cache

MyBatis’s first-level cache

  • The first-level cache is at the SqlSession level. Data queried through the same SqlSession will be cached. The next time you query the same data, it will be obtained directly from the cache and will not be revisited from the database.

  • Four situations that invalidate the first-level cache:

    1. Different SqlSession corresponds to different first-level cache
    2. The same SqlSession but different query conditions
    3. Any addition, deletion, and modification operations were performed during two queries on the same SqlSession.
    4. The cache was manually cleared during two queries on the same SqlSession.

MyBatis’s second-level cache

  • The second-level cache is at the SqlSessionFactory level. The results of SqlSession queries created through the same SqlSessionFactory will be cached; if the same query statement is executed again thereafter, the results will be obtained from the cache.

  • Conditions for enabling second-level cache

    1. In the core configuration file, set the global configuration attribute cacheEnabled=”true”. The default is true and does not need to be set.
    2. Set labels in mapping files
    3. The second level cache must be valid after the SqlSession is closed or committed
    4. The entity class type converted by the query data must implement the serialization interface
  • Invalidation of the second-level cache: Any additions, deletions, and modifications performed between two queries will invalidate both the first-level and second-level caches at the same time.

Level 2 cache related configuration

  • The cache tag added in the mapper configuration file can set some properties
  • eviction attribute: cache recycling strategy
  • LRU (Least Recently Used) – Least Recently Used: Remove objects that have not been used for the longest time.
    • FIFO (First in First out) – Remove objects in the order they enter the cache.
    • SOFT – Soft Reference: Removes objects based on garbage collector status and soft reference rules.
    • WEAK – Weak References: More aggressively remove objects based on garbage collector state and weak reference rules.
    • The default is LRU
  • flushInterval attribute: refresh interval, in milliseconds
  • The default is not set, that is, there is no refresh interval. The cache is only refreshed when statements (add, delete, modify) are called.
  • size attribute: number of references, positive integer
  • Represents the maximum number of objects that the cache can store. If it is too large, it may cause memory overflow.
  • readOnly attribute: read-only, true/false
  • true: read-only cache; will return the same instance of the cache object to all callers. Therefore these objects cannot be modified. This provides important performance advantages.
    • false: Read and write cache; will return a copy of the cache object (via serialization). This is slower, but safer, so defaults to false

MyBatis cache query order

  • Query the second-level cache first, because there may be data in the second-level cache that has been found by other programs and can be used directly.
  • If there is no hit in the second-level cache, query the first-level cache again.
  • If there is no hit in the first level cache, query the database
  • After SqlSession is closed, the data in the first-level cache will be written to the second-level cache.

Integrate third-party cache EHCache (understand)

Add dependencies

<!-- Mybatis EHCache integration package -->
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.2.1</version>
</dependency>
<!-- A specific implementation of the slf4j log facade -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>

Functions of each jar package

jar package name Function
mybatis-ehcache Mybatis and EHCache integration package
ehcache EHCache core package
slf4j -api SLF4J log facade package
logback-classic Supports a specific implementation of the SLF4J facade interface

Create the EHCache configuration file ehcache.xml

  • The name must be ehcache.xml
<?xml version="1.0" encoding="utf-8" ?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
    <!-- Disk save path -->
    <diskStore path="D:\atguigu\ehcache"/>
    <defaultCache
            maxElementsInMemory="1000"
            maxElementsOnDisk="10000000"
            eternal="false"
            overflowToDisk="true"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
    </defaultCache>
</ehcache>

Set the type of second-level cache

  • Set the second-level cache type in the xxxMapper.xml file
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

Add logback log

  • When SLF4J exists, log4j as a simple log will be invalid. At this time, we need to use the specific implementation of SLF4J logback to print the log. Create a logback configuration file logback.xml. The name is fixed and cannot be changed.
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">
    <!-- Specify the location of log output -->
    <appender name="STDOUT"
              class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <!-- Log output format -->
            <!-- In order: time, log level, thread name, log printing class, log body content, newline -->
            <pattern>[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger] [%msg]%n</pattern>
        </encoder>
    </appender>
    <!-- Set the global log level. The log levels in order are: DEBUG, INFO, WARN, ERROR -->
    <!-- Specifying any log level will only print logs of the current level and subsequent levels. -->
    <root level="DEBUG">
        <!-- Specify the appender for printing logs, here the appender configured earlier is referenced through "STDOUT" -->
        <appender-ref ref="STDOUT" />
    </root>
    <!-- Specify local log levels according to special needs -->
    <logger name="com.atguigu.crowd.mapper" level="DEBUG"/>
</configuration>

EHCache configuration file description

Attribute name Is it necessary Function
maxElementsInMemory Yes The maximum number of elements cached in memory
maxElementsOnDisk Yes The maximum number of elements cached on disk, if 0 means infinity
eternal Yes Set whether cached elements never expire. If it is true, the cached data is always valid. If it is false, it must be judged based on timeToIdleSeconds and timeToLiveSeconds
overflowToDisk Yes Set whether to cache expired elements on disk when the memory cache overflows
timeToIdleSeconds No When When the time between two accesses to the data cached in EhCache exceeds the value of the timeToIdleSeconds attribute, the data will be deleted. The default value is 0, which means the idle time is infinite
timeToLiveSeconds No The effective lifetime of the cache element, the default is 0., that is, the element survival time is infinite
diskSpoolBufferSizeMB No The cache size of DiskStore (disk cache). The default is 30MB. Each Cache should have its own buffer
diskPersistent No Whether to enable disk saving when the VM restarts The data in EhCache, the default is false
diskExpiryThreadIntervalSeconds No The disk cache cleaning thread running interval, the default is 120 seconds . Every 120s, the corresponding thread will clean up the data in EhCache
memoryStoreEvictionPolicy No When the memory cache reaches Maximum, when a new element is added, the strategy of removing the element in the cache. The default is LRU (least recently used), the options are LFU (least frequently used) and FIFO (first in first out