1. Pre-knowledge
The cache is introduced
There are two caches in MyBatis, level 1 cache and level 2 cache
Level 1 cache: Also known as session-level cache, the life cycle only exists for the current session and cannot be turned off or off. Level-1 cache cannot use level-2 cache across threads (disabled by default) : application-level cache. Cache objects exist throughout the application cycle and can be used across threads. Level-2 cache has a higher hit ratio and is suitable for caching data that is less modified. The process accesses level 2 cache first and level 1 cache later. Usage scenarios: Static tables, dictionary tables, permission tables are generally used in the level 2 cache
Mybatis level 1 cache and level 2 cache final implementation
classification
Level 1 cache implementation:
A level 1 cache is made up of a BaseExecutor executor, a level 1 cache, a transaction management commonality. A Level 1 cache consists directly of a localCache of type PerpetualCache of BaseExecutor
Implementation of two level cache The composition of the second level cache: the second level cache by SqlSession, CachingExecutor, TransactionalCacheManager, TransactionalCache, then the class TransactionalCache delegate refers to the staging area To the chain of responsibility, the end of the chain of responsibility is the second level cache storage class of SqlSession, CachingExecutor, TransactionalCacheManager, are SqlSession TransactionalCache life cycle
In common
1 The implementations of both primary and secondary caches are PerpetualCache classes, which maintain a HashMap as a data structure stored in the cache
2 cache key and value are created the same,The implementation of level 1 cache is a HashMap,value is a cache value, generally a List data set, and key is a key created based on SQL statements, paging query parameters,Statement IDS, and Mapper
The difference between
Level 1 caches are lifetime caches that exist in the current session, not across sessions, and can only be held by one thread
Level 2 cache life cycle exists in the current application, can be used across threads, level 2 cache has a higher hit ratio, suitable for caching some less modified data. The process accesses level 2 cache first and level 1 cache later
The level 3 cache is updated in real time. The cache is updated as soon as the data is checked from the database
4 Level 2 cache update Requires the current session COMMIT operation to update level 2 cache
Primary and secondary cache code analysis for a simple query
@Test
public void cacheTest6() {
SqlSession session1 = factory.openSession(true);
session1.getMapper(UserMapper.class).selectByid(1);
session1.getMapper(BlogMapper.class).selectById(1);
System.out.println(session1);
}
Copy the code
Debug breakpoints in system.out.println
Specific implementations such as level 1 caching and transaction management exist in BaseExecutor, which is used to deal with the common problems of the three actuators. The Delegate attribute of the CachingExecutor level 2 cache executor points to BaseExecutor
2 The CachingExecutor delegate property points to the executor. TCM is a transaction cache manager with multiple extents, each of which points indirectly to the PerpetualCache class that stores the second-level cache at the end of the responsibility chain
3. Each staging area points to the secondary cache at the end of a single responsibility chain, and each secondary cache can be pointed to by multiple staging areas
Mybatis level 1 cache and level 2 cache design purpose
The design purpose of level 1 cache
Goal 1: For integration with Spring’s declarative transactions,Mybatis is a JDBC data source for Spring without transactions Transaction refers to: multiple SQL add, delete, change query request is the same connection, this connection is not automatically submitted, and so on after the execution of a number of add, delete, change query SQL, submit together, open the connection, and submit the connection, the middle execution of the SQL statement is called a transaction.
Objective 2: If a level 1 cache is not present, Mybatis will not even execute nested queries
Objective 3: It is very common and normal to execute the same SQL statement multiple times in the same session. There is no need to query the database. Level 2 cache can be omitted, but level 1 cache must be present
Objective 4: In some cases, level 1 caching is related to circular dependencies of nested queries
Level 2 cache design purpose
Objective 1: Reduce the number of I/O requests from the back-end server. The cache object exists throughout the application cycle. The level-2 cache has a higher hit ratio and is suitable for caching data that is less modified. The process accesses level 2 cache first and level 1 cache later.
Objective 2: Sometimes queries, especially circular queries, are slow, so using level 2 caching is a good idea
Disadvantages: 1 It is risky to enable all level 2 cache and may cause some data inconsistency. 2 Level 2 cache, which uses JDK serialization and deserialization to cache data objects, is inefficient. 3 It can only be used in a single machine, and distributed cache Redis is recommended
Mybatis level 1 cache and level 2 cache features
Level-1 Cache feature 1 If level-1 cache hits, the resulting dataset is the same, that is, two references point to the same dataset 2 If the ReuseExecutor is used and the SAME SQL is invoked in the same session, statement level 2 caching feature 1 will be reused even if the parameters are different,StatementID is different, and Mapper is different If the second level cache hit, the data set is not the same, because through the chain of responsibility in the process of the second level cache storage SerializedCache will store the data, and take out the data into the JDK serialization and deserialization, so the data object is not the same, the default from the cache to retrieve the key corresponding to the object is not the same, Because SerializedCache serializes putObject data and getObject data, both get the same key and get different objects
@Test public void cacheTest4() { Cache cache = configuration.getCache("org.coderead.mybatis.UserMapper"); User user = Mock.newUser(); cache.putObject("luban", user); 1 Object luban = cache.getobject ("luban"); // thread 2 Object luban1 = cache.getobject ("luban"); System.out.println(luban==luban1); }Copy the code
The second level cache must be filled after the session commits. Level 2 cache is not updated in real time, and it needs a place to store the changed data temporarily, namely the staging area. In the design of level 2 cache structure, each session has several staging areas, all of which are managed by a unified transaction session manager
Why can’t a second level cache be hit until it’s committed? Standard answer (in order to ensure data integrity, the second level cache must be committed by the session before it can be filled (does not take effect after rollback)), because the second level cache structure design complexity is increased a lot because the second level cache can be hit after the commit
As shown in the figure above, when two sessions modify the same data, session 2 will query it after modification. If it is filled into the second-level cache in real time, session 1 can get the modified data through the cache. However, in fact, the modified data is rolled back and not really submitted to the database.
Therefore, in order to ensure the integrity of the data, the level 2 cache must be committed by the session before it is filled (it does not take effect after rollback), including the clearing of the cache, and it must take effect after the normal session commits.
The session, the staging area, and the transaction manager are all part of the same entity, and will be destroyed as soon as the session ends, but the Mapper namespace of the level 2 cache will always exist, and the application level life cycle will always exist as long as the program is running.
4. Analysis of each node in the responsibility chain
5 if a Mapper update operation is performed (update,delete,insert in any namespace will invalidate the secondary cache)Clears all data in the current Mapper cache space. Setting this annotation does not
Level 2 cache configuration policy
Description: The level-2 default cache is disabled by default. You need to specify a cache space for the level-2 default cache, such as @cachenamespace or a specified MappedStatement. After the declaration, the cache is unique to the Mapper and cannot be accessed by any other Mapper. If multiple Mappers need to share a cache space, you can use @cachenamespaceref or reference the same cache space. For details, see the following table:
@ CacheNamespace annotations
Configuration description:
1 implementation specifies the cache implementation class, the default is to store the cache in memory with HashMap, the default is to store the cache with HashMap, the default is to store the cache with HashMap, the default is to store the cache with HashMap. 3 flushInterval Sets the time at which the cache is flushed completely. The default value is not flushed (the entire cache is flushed). The default value is 0, indicating that the cache is permanently valid. The cache capacity will be designed to be disabled when the cache is larger than the specified eviction algorithm. ReadWrite true is designed to ensure that the cache object is readable and writable, default is true, blocking lock is required for each Key block, blocking lock is required. 7 properties For the above components, configure additional parameters, key corresponds to the field name of the component, and add the related attribute \ to the cache
The declared cache space does not mean that all SQL requests in the current application go through this cache space. Each cache space specifies a MappedStatement. Only CRUD operations under the current MappedStatement can use this level of cache
@options (methods for Mapper interface)