1. MyBatis first level cache and second level cache
When executing a query SQL, the process is
- Query from secondary storage
- Enter the query in the first-level storage to execute JDBC query.
- The order of the cache: second-level cache; first-level cache: database
L1 cache
-
The data queried during the same session with the database will be placed in the local cache.
- If you need to obtain the same data in the future, you can get it directly from the cache, and there is no need to query the database again;
-
By default, only the first level cache (SqlSession level cache, also known as local cache) is enabled,
-
Level 1 cache is always on;
- A Map at the SqlSession level
L2 cache
-
global cache
-
The second-level cache needs to be manually enabled and configured. It is based on the namespace-level cache, and a namespace corresponds to a second-level cache:
-
In order to improve scalability. MyBatis defines the cache interface Cache.
- We can customize the second-level cache by implementing the Cache interface
- After the first-level cache is closed, it is put into the second-level cache.
* Working Mechanism: * 1,A session, query a piece of data, this data will be placed in the first level cache of the current session; * 2,If the session is closed, the data in the first-level cache will be saved in the second-level cache; the new session query information can refer to the content in the second-level cache; * 3,sqlSession===EmployeeMapper==>Employee * DepartmentMapper===>Department * different namespace The detected data will be placed in its corresponding cache ( map) * Effect: data will be obtained from the second level cache * The detected data will be placed in the first level cache by default. * Only after the session is committed or closed, the data in the first level cache will be transferred to the second level cache * use: * 1),Enable the global L2 cache configuration:<setting name="cacheEnabled" value="true"/> * 2),go mapper.xml Configure the use of second-level cache in: * <cache></cache> * 3),our POJO Need to implement serialization interface. public class Employee implements Serializable{
4 cases of L1 cache failure
* The failure of the first-level cache (if the current level-1 cache is not used, the effect is that it needs to send a query to the database): * 1,sqlSession different. * 2,sqlSession Same, different query conditions.(There is no such data in the current first-level cache) * 3,sqlSession Same, additions, deletions, and modifications were performed between the two queries(This addition, deletion and modification may have an impact on the current data) * 4,sqlSession Same, manually cleared the first level cache (cache empty)
Manually clear the level 1 cache
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); SqlSession openSession = sqlSessionFactory.openSession(); //4. The sqlSession is the same, and the first-level cache is manually cleared (cache is cleared) //openSession.clearCache();
getSqlSessionFactory tool class
public SqlSessionFactory getSqlSessionFactory() throws IOException { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); return new SqlSessionFactoryBuilder().build(inputStream); }
L2 cache
turn on
<settings> <setting name="mapUnderscoreToCamelCase" value="true"/> <!--Explicitly specify the value of each configuration we need to change, even if it is the default. Prevent problems caused by version updates --> <setting name="cacheEnabled" value="true"/> The second-level cache is enabled by default, and we display the configuration. <setting name="lazyLoadingEnabled" value="true"/> </settings>
Configuration and Recycling Policies
- In each Mapper.xml configuration
<!--<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>--> <cache eviction="FIFO" flushInterval="60000" readOnly="false" size="1024"></cache> <!-- eviction:Cache recycling strategy: • LRU – Least Recently Used: Removes objects that have not been used for the longest time. • FIFO – First in, first out: objects are removed in the order they entered the cache. • SOFT – Soft references: Remove objects based on garbage collector state and soft reference rules. Accept if there is not enough memory. • WEAK – Weak References: More aggressively remove objects based on garbage collector state and weak reference rules. When garbage is collected, it is always recycled. • default is LRU. type="": Specify the full class name of the custom cache; implement Cache Just the interface; -->
- java four major references, strong and weak
Close the session and put it into the second-level cache
openSession.close();//Only when the session is turned off will it be put into the secondary cache. //Clear the first level cache of the current session;
Refer to a cache under a namespace
<!-- Reference cache: namespace: Specify the same as the cache under which namespace --> <cache-ref namespace="com.atguigu.mybatis.dao.EmployeeMapper"/>
See the documentation below for related settings
For each CRUD tag: flushCache="true": (Level 1 and level 2 will be cleared)
Integrate ehcache cache
* Third-party cache integration: * 1),Just import the third-party cache package; * 2),Import the adapter package integrated with the third-party cache; officially available; * 3),mapper.xml Use a custom cache in Cache package, including: ehcache-core-2.6.8jar sl4j-api-1.6.1jar slf4j-log412-1.6.2.jar
<dependency> <groupId>org.mybatis.caches</groupId> <artifactId>mybatis-ehcache</artifactId> <version>1.1.0</version> </dependency> //February 14, 2023 <version>1.2.3</version>
<mapper namespace="org.acme.FooMapper"> <cache type="org.mybatis.caches.ehcache.EhcacheCache"/> ... </mapper>
ehcache.xml
- Put it under the classpath:
<!-- Disk save path --> <diskStore path="D:\44\ehcache" />
MyBatis-Cache Mechanism Detailed Documentation
- March 4, 2017
1. Basic understanding of level 1 and level 2
MyBatis includes a very powerful query cache feature, which can be configured and customized very easily. Caching can greatly improve query efficiency. • Two-level cache is defined by default in MyBatis system.
• L1 cache and
- local cache
Second level cache.
- global cache
– 1. By default, only the first level cache (SqlSession level cache, also called local cache) is enabled.
– 2. The second-level cache needs to be manually enabled and configured. It is based on the namespace-level cache.
– 3. To improve scalability. MyBatis defines the cache interface Cache. We can customize the second-level cache by implementing the Cache interface
2. Universal Acquisition Factory
public SqlSessionFactory getSqlSessionFactory() throws IOException { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); return new SqlSessionFactoryBuilder().build(inputStream); }
3. Level 1 cache text description
* Two-level cache: * Level 1 cache: (local cache): sqlSession level cache. Level 1 cache is always on; SqlSession level one Map * The data queried during the same session with the database will be placed in the local cache. * If you need to obtain the same data in the future, you can get it directly from the cache, and there is no need to query the database again; * <p> * * The failure of the first-level cache (if the current level-1 cache is not used, the effect is that it needs to send a query to the database): * 1,sqlSession different. * 2,sqlSession Same, different query conditions.(There is no such data in the current first-level cache) * 3,sqlSession Same, additions, deletions, and modifications were performed between the two queries(This addition, deletion and modification may have an impact on the current data) * 4,sqlSession Same, manually cleared the first level cache (cache empty)
4. Demonstration of Level 1 Cache Invalidation
@Test public void testFirstLevelCache() throws IOException { SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); SqlSession openSession = sqlSessionFactory.openSession(); try { EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class); //Query twice in a row, the objects are equal Employee emp01 = mapper.getEmpById(1); System.out.println(emp01); //xxxxx //1. The sqlSession is different. //SqlSession openSession2 = sqlSessionFactory.openSession(); //EmployeeMapper mapper2 = openSession2.getMapper(EmployeeMapper.class); //2. The sqlSession is the same, but the query conditions are different //3. The sqlSession is the same, and the addition, deletion, and modification operations are performed between the two queries (this addition, deletion, and modification may have an impact on the current data) //mapper.addEmp(new Employee(null, "testCache", "cache", "1")); //System.out.println("Data added successfully"); //4. The sqlSession is the same, and the first-level cache is manually cleared (cache is cleared) //openSession.clearCache(); Employee emp02 = mapper.getEmpById(1); //Employee emp03 = mapper.getEmpById(3); System.out.println(emp02); //System.out.println(emp03); System.out.println(emp01 == emp02); //openSession2.close(); } finally { openSession.close(); } }
5. L2 cache
turn on
<settings> <setting name="mapUnderscoreToCamelCase" value="true"/> <setting name="jdbcTypeForNull" value="NULL"/> <!--Explicitly specify the value of each configuration we need to change, even if it is the default. Prevent problems caused by version updates --> <setting name="cacheEnabled" value="true"/> The second-level cache is enabled by default, and we display the configuration. <setting name="lazyLoadingEnabled" value="true"/> <setting name="aggressiveLazyLoading" value="false"/> </settings>
detailed configuration
<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache> <!-- <cache eviction="FIFO" flushInterval="60000" readOnly="false" size="1024"></cache> --> <!-- eviction:Cache recycling strategy: • LRU – Least Recently Used: Removes objects that have not been used for the longest time. • FIFO – First in, first out: objects are removed in the order they entered the cache. • SOFT – Soft references: Remove objects based on garbage collector state and soft reference rules. Accept if there is not enough memory. • WEAK – Weak References: More aggressively remove objects based on garbage collector state and weak reference rules. When garbage is collected, it is always recycled. • default is LRU. flushInterval: cache refresh interval How often the cache is cleared, the default is not cleared, set a millisecond value readOnly:Is it read-only: true: read only; mybatis It is considered that all operations to obtain data from the cache are read-only operations and will not modify the data. mybatis In order to speed up the acquisition, the reference of the data in the cache is directly handed over to the user. unsafe, fast false: Not read-only: mybatis It is felt that the acquired data may be modified. mybatis Will use serialization&The anti-sequence technology clones a new data for you. safe, slow size: How many elements are stored in the cache; type="": Specify the full class name of the custom cache; accomplish Cache Just the interface; -->
test
@Test public void testSecondLevelCache() throws IOException { SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); SqlSession openSession = sqlSessionFactory.openSession(); SqlSession openSession2 = sqlSessionFactory.openSession(); try { //1, EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class); EmployeeMapper mapper2 = openSession2.getMapper(EmployeeMapper.class); Employee emp01 = mapper.getEmpById(1); System.out.println(emp01); openSession.close();//Only when the session is turned off will it be put into the secondary cache. //The second query is the data obtained from the second-level cache, and no new sql is sent //mapper2.addEmp(new Employee(null, "aaa", "nnn", "0")); Employee emp02 = mapper2.getEmpById(1); System.out.println(emp02); openSession2.close(); } finally { } }
L2 cache text
* L2 cache: (global cache): based on namespace Level of caching: one namespace Corresponding to a secondary cache: * Working Mechanism: * 1,A session, query a piece of data, this data will be placed in the first level cache of the current session; * 2,If the session is closed, the data in the first-level cache will be saved in the second-level cache; the new session query information can refer to the content in the second-level cache; * 3,sqlSession===EmployeeMapper==>Employee * DepartmentMapper===>Department * different namespace The detected data will be placed in its corresponding cache ( map) * Effect: data will be obtained from the second level cache * The detected data will be placed in the first level cache by default. * Only after the session is committed or closed, the data in the first level cache will be transferred to the second level cache * use: * 1),Enable the global L2 cache configuration:<setting name="cacheEnabled" value="true"/> * 2),go mapper.xml Configure the use of second-level cache in: * <cache></cache> * 3),our POJO Need to implement serialization interface. public class Employee implements Serializable{
6. Settings related to caching
- cacheEnabled=true
- Each select tag has useCache="true"
- For each addition, deletion and modification of tags: flushCache="true"
- Query tag: flushCache="false"
- sqlSession.clearCache()
- localCacheScope: local cache scope
* Settings related to caching/Attributes: * 1),cacheEnabled=true: false: Close the cache (secondary cache closed)(Level 1 cache is always available) * * 2),each select tags have useCache="true": * false: Do not use cache (level 1 cache is still used, level 2 cache is not used) * 3),[For each CRUD tag: flushCache="true": (Level 1 and level 2 will be cleared)] * The cache will be cleared after the addition, deletion and modification are completed; * test: flushCache="true": The first level cache is cleared; the second level will also be cleared; * * Query tags: flushCache="false": Queries are not cached. * if flushCache=true;The cache is cleared after each query; the cache is not used; * * * 4),sqlSession.clearCache();just clear the present session the first level cache; * 5),localCacheScope: Local cache scope: (Level 1 cache SESSION);All data for the current session is stored in the session cache; still configured in:<settings> Bar * STATEMENT: Level 1 cache can be disabled;
7. Summary
-
Level 2 cache: (global cache): cache based on namespace level: a namespace corresponds to a level 2 cache:
-
Level 1 cache: (local cache): sqlSession level cache. The first-level cache is always open; a Map at the SqlSession level
- After the first-level cache is closed, it is put into the second-level cache.
-
If there is a new reply, if there is a second-level cache, let's look at the second-level cache first.
- The order of the cache: second-level cache; first-level cache: database
-
Based on: PerpetualCache
- Also: FifoCache, LruCache, SerializedCache
public class PerpetualCache implements Cache { private Map<Object, Object> cache = new HashMap(); }
8. Integrate ehcache cache
- Cache interface provided by MyBatis
public interface Cache { String getId(); void putObject(Object var1, Object var2); Object getObject(Object var1); Object removeObject(Object var1); void clear(); int getSize(); ReadWriteLock getReadWriteLock(); }
- import ehcache
ehcache-core-2.6.8jar sl4j-api-1.6.1jar slf4j-log412-1.6.2.jar
<dependency> <groupId>org.mybatis.caches</groupId> <artifactId>mybatis-ehcache</artifactId> <version>1.1.0</version> </dependency> //February 14, 2023 <version>1.2.3</version>
use
* Third-party cache integration: * 1),Just import the third-party cache package; * 2),Import the adapter package integrated with the third-party cache; officially available; * 3),mapper.xml Use a custom cache in
<mapper namespace="org.acme.FooMapper"> <cache type="org.mybatis.caches.ehcache.EhcacheCache"/> ... </mapper>
ehcache.xml
- Put it under the classpath:
<?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:\44\ehcache" /> <defaultCache maxElementsInMemory="10000" maxElementsOnDisk="10000000" eternal="false" overflowToDisk="true" timeToIdleSeconds="120" timeToLiveSeconds="120" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU"> </defaultCache> </ehcache> <!-- Property description: l diskStore: Specifies where the data is stored on disk. l defaultCache: when using CacheManager.add("demoCache")create Cache hour, EhCache will use<defalutCache/>specified management policy The following attributes are required: l maxElementsInMemory - cached in memory element maximum number of l maxElementsOnDisk - cached on disk element The maximum number of , if 0 means infinity l eternal - set cached elements Whether never expires. if for true,The cached data is always valid, if false Then according to timeToIdleSeconds,timeToLiveSeconds judge l overflowToDisk - Set whether to expire when the memory cache overflows element cache to disk The following attributes are optional: l timeToIdleSeconds - when cached in EhCache The data in the data is accessed twice before and after more than timeToIdleSeconds These data will be deleted when the attribute value is set, the default value is 0,That is, the idle time is infinite l timeToLiveSeconds - cache element The effective lifetime, the default is 0.,that is element Survival time is infinite diskSpoolBufferSizeMB This parameter setting DiskStore(disk cache)buffer size for.The default is 30 MB.each Cache Each should have its own buffer. l diskPersistent - exist VM Whether to enable disk saving when restarting EhCache data in , the default is false. l diskExpiryThreadIntervalSeconds - The running interval of the disk cache cleaning thread, the default is 120 seconds. 120 each s,The corresponding thread will perform a EhCache Data cleaning in l memoryStoreEvictionPolicy - When the memory cache reaches its maximum, there are new element When joining, remove the cache element strategy. default is LRU(least recently used), optional LFU(least commonly used) and FIFO(first in first out) -->
- Introduce caching
<!-- Reference cache: namespace: Specify the same as the cache under which namespace --> <cache-ref namespace="com.atguigu.mybatis.dao.EmployeeMapper"/>
9. Cache schematic diagram
client ——> a session sqlsession object ——> CachingExecutor ——> Executor ——> Database
A session sqlsession object, including the following two objects:
- CachingExecutor -> Executor
- Among them: Executor object: After the query, it is cached in the first-level cache Local cache Local Cache
configuration object
-
Internal storage L2 cache - you can call a custom cache such as MemCached
-
When executing a query SQL, the process is
Query from secondary storage
Enter the first-level storage query to execute JDBC query.