The simple configuration tutorial of the second-level cache explains the effect of the second-level cache

This article is mainly about the introduction of the second-level cache, and focuses on the whole process of the simple configuration of the second-level cache. I hope this article will give you a deeper understanding of the second-level cache.

Secondary cache

The CPU cache (Cache Memory) is a temporary storage between the CPU and the memory. Its capacity is smaller than the memory but the exchange speed is faster. The data in the cache is a small part of the memory, but this small part is about to be accessed by the CPU in a short time. When the CPU calls a large amount of data, it can avoid the memory and call it directly from the cache, thereby speeding up the reading speed. . Initially, the cache was only level one, and the second level cache (L2 CACHE) appeared to coordinate the speed between the level one cache and the memory. The second-level cache is slower than the first-level cache and has a larger capacity. It is mainly used for temporary exchange of data between the first-level cache and the memory. In fact, Intel and AMD processors are different in the logical structure design of the first level cache, so the impact of the second level cache on the CPU performance is also different.

Cache refers to the memory that can exchange data at a high speed. It exchanges data with the CPU before the memory, so the speed is very fast. L1Cache (first level cache) is the first level of CPU cache. The capacity and structure of the built-in L1 cache have a greater impact on the performance of the CPU, but the cache memory is composed of static RAM, and the structure is more complex. When the CPU die area cannot be too large, the capacity of the L1 cache is not It may be too big. Generally, the capacity of L1 cache is usually 32-256KB. L2Cache (second-level cache) is the second-level cache of the CPU, divided into internal and external chips. The internal second-level cache of the chip runs at the same speed as the main frequency, while the external second-level cache is only half of the main frequency. The L2 cache capacity will also affect the performance of the CPU. The principle is that the larger the better, the L2 cache of ordinary desktop CPUs is generally 128KB to 2MB or higher, and the L2 cache of CPUs used on notebooks, servers and workstations can reach up to 1MB. -3MB.

Detailed explanation of the simple configuration tutorial of the second-level cache. Talking about the effect of the second-level cache

Detailed tutorial on simple configuration of secondary cache

This tutorial takes MyBatis secondary cache settings as an example.

One, the complete process of creating Cache

We start with SqlSessionFactoryBuilder parsing the mybaTIs-config.xml configuration file:

Reader reader = Resources.getResourceAsReader("mybaTIs-config.xml");

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);

After that:

XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properTIes);

return build(parser.parse());

Look at the parser.parse() method:

parseConfiguraTIon(parser.evalNode("/configuration"));

Look at where the Mapper.xml file is processed:

mapperElement(root.evalNode("mappers"));

Look at the XMLMapperBuilder that processes Mapper.xml:

XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration,

resource, configuration.getSqlFragments());

mapperParser.parse();

Continue to look at the parse method:

configurationElement(parser.evalNode("/mapper"));

to here:

String namespace = context.getStringAttribute("namespace");

if (namespace.equals("")) {

throw new BuilderException("Mapper's namespace cannot be empty");

}

builderAssistant.setCurrentNamespace(namespace);

cacheRefElement(context.evalNode("cache-ref"));

cacheElement(context.evalNode("cache"));

From here, you can see that namespace is the attribute of the "mapper" element in xml. Then the following are the cache-refs and caches that are processed successively. The latter cache will overwrite the previous cache-ref, but if the referenced cache is not found by the cache-ref at the beginning, it will not be overwritten and will continue until the final processing is completed. , Finally, if there is a cache, it will be overwritten by cache-ref instead. Is it a bit dizzy and messy here? So don't configure these two at the same time, in fact, very few people do.

Take a look at how MyBatis handles "cache/":

private void cacheElement (XNode context) throws Exception {

if (context!= null) {

String type = context.getStringAttribute("type", "PERPETUAL");

Class "? extends Cache" typeClass = typeAliasRegistry.resolveAlias(type);

String eviction = context.getStringAttribute("eviction", "LRU");

Class "? extends Cache" evictionClass = typeAliasRegistry.resolveAlias(eviction);

Long flushInterval = context.getLongAttribute("flushInterval");

Integer size = context.getIntAttribute("size");

boolean readWrite =! context.getBooleanAttribute("readOnly", false);

boolean blocking = context.getBooleanAttribute("blocking", false);

Properties props = context.getChildrenAsProperties();

builderAssistant.useNewCache(typeClass, evictionClass,

flushInterval, size, readWrite, blocking, props);

}

}

From the source code, you can see that MyBatis has read those attributes, and it is easy to get the default values ​​of these attributes.

The method to create a Java cache object is builderAssistant.useNewCache. Let's take a look at this code:

public Cache useNewCache(Class "? extends Cache" typeClass,

Class "? extends Cache" evictionClass,

Long flushInterval,

Integer size,

boolean readWrite,

boolean blocking,

Properties props) {

typeClass = valueOrDefault(typeClass, PerpetualCache.class);

evictionClass = valueOrDefault(evictionClass, LruCache.class);

Cache cache = new CacheBuilder(currentNamespace)

.implementation(typeClass)

.addDecorator(evictionClass)

.clearInterval(flushInterval)

.size(size)

.readWrite(readWrite)

.blocking (blocking)

.properties (props)

.build();

configuration.addCache(cache);

currentCache = cache;

return cache;

}

From the place where this method is called, we can see that the return value cache is not used, and currentCache is used when the MappedStatement is created in the subsequent process.

Second, use the Cache process

In the system, the place where Cache is used is in CachingExecutor:

@Override

public "E" List "E" query(

MappedStatement ms, Object parameterObject,

RowBounds rowBounds, ResultHandler resultHandler,

CacheKey key, BoundSql boundSql) throws SQLException {

Cache cache = ms.getCache();

After obtaining the cache, first determine whether there is a second-level cache.

Only through "cache/", "cache-ref/" or @CacheNamespace, @CacheNamespaceRef tags to use the cached Mapper.xml or Mapper interface (the same namespace, can not be used at the same time) will there be a secondary cache.

if (cache!= null) {

If the cache exists, it will determine whether to clear the cache according to the flushCache attribute of the SQL configuration ("insert", "select", "update", "delete".

flushCacheIfRequired(ms);

Then determine whether to use the cache according to the attribute useCache of the xml configuration (the default value generally used by resultHandler, which is rarely null).

if (ms.isUseCache() && resultHandler == null) {

Make sure that the method has no parameters of type Out. Mybatis does not support the caching of stored procedures, so if it is a stored procedure, an error will be reported here.

ensureNoOutParams(ms, parameterObject, boundSql);

After there is no problem, the value will be taken from the cache according to the key:

@SuppressWarnings("unchecked")

List "E" list = (List "E") tcm.getObject(cache, key);

If there is no cache, the query will be executed and the query result will be placed in the cache.

if (list == null) {

list = delegate. "E" query(ms, parameterObject,

rowBounds, resultHandler, key, boundSql);

tcm.putObject(cache, key, list); // issue #578 and #116

}

Return result

return list;

}

}

When there is no cache, execute the query directly

return delegate. "E" query (ms, parameterObject, rowBounds, resultHandler, key, boundSql);

}

In the above code, tcm.putObject(cache, key, list); this code is the result of caching. But in fact, until sqlsession is closed, MyBatis is saved in a Map (default cache configuration) in a serialized form.

Three, precautions when using Cache

1. Cache can only be used on tables with [only single table operation]

Not only is it necessary to ensure that this table has only a single table operation in the entire system, but all operations related to this table must all be under one namespace.

2. Use the cache when you can ensure that the query is much larger than the insert, update, and delete operations

There is no need to say more about this, everyone should be clear. Remember, this needs to be guaranteed under the premise of 1!

Fourth, avoid the use of secondary cache

There may be many people who do not understand this, the benefits of the second-level cache are far less than the hidden dangers.

The cache is based on the namespace, and operations under different namespaces do not affect each other.

The insert, update, and delete operations will clear all caches under the namespace where they are located.

Usually in the code generated by MyBatis Generator, each table is independent, and each table has its own namespace.

Why avoid second-level cache

There is no harm when it meets the requirements of [Precautions when using Cache].

There will be a lot of harm in other situations.

Certain operations on a table are not performed under its independent namespace.

For example, there are most operations on the user table in UserMapper.xml. But in a XXXMapper.xml, there are also operations for user single tables.

This will result in inconsistent user data in the two namespaces. If you refresh the cache in UserMapper.xml, the cache in XXXMapper.xml is still valid. If there is a single table query for user, the result of using the cache may be incorrect.

A more dangerous situation is that when insert, update, and delete operations are performed in XXXMapper.xml, various operations in UserMapper.xml will be full of unknowns and risks.

Operations related to such a single table may not be common. But you may think of a common situation.

Multi-table operations must not use caching

Why not?

First of all, no matter which namespace the multi-table operation is written to, there will be cases where a certain table is not in this namespace.

For example, there are two tables: role and user_role. If I want to query all the roles of a user, it will definitely involve multiple tables.

"Select id="selectUserRoles" resultType="UserRoleVO""

select * from user_role a, role b where a.roleid = b.roleid and a.userid = #{userid}

"/Select"

Like the above query, which xml will you write? ?

Whether it is written to RoleMapper.xml or UserRoleMapper.xml, or a separate XxxMapper.xml. If the second-level cache is used, the result of the above query may be incorrect.

If you happen to modify the role of this user, the result of the above query will be wrong when the cache is used.

This should be easy to understand.

In my opinion, it is unsolvable based on the current caching method of MyBatis. Multi-table operations cannot be cached at all.

If you let them all use the same namespace (through "cache-ref") to avoid dirty data, it loses the meaning of caching.

Seeing this, in fact, it means that the second-level cache cannot be used. It's useless to introduce so much in the whole article.

5. Save the secondary cache?

If you want to use the second-level cache more efficiently, it can't be solved.

But there is still a way to solve multi-table operations to avoid dirty data. The solution is to use the interceptor to determine which tables are involved in the executed sql (can be parsed with jsqlparser), and then automatically empty the cache of the related tables. However, the use efficiency of the cache in this way is very low.

Designing such a plug-in is quite complicated, and since I didn't plan to implement it, no nonsense.

Conclusion

This is the end of the introduction to the second-level cache. I hope this article will give you a deeper understanding of the second-level cache. If you have any deficiencies, please correct me.

Titanium Sunglasses

Titanium Sunglasses,Eyewear Titanium,Titanium Frame Sunglasses,Sunglasses With Titanium Frames

Danyang Hengshi Optical Glasses Co., Ltd. , https://www.hengshi-optical.com

Posted on