This is the second day of my participation in Gwen Challenge

Definition of:

The cache is the data in memory, often from the database query results saved, using the cache, we can avoid frequent interaction with the database, and thus improve the response speed

Mybatis also supports data caching, which is divided into level 1 cache and level 2 cache. You can understand the scope of level 1 cache and level 2 cache through the following figure:

As you can see

  1. Level 1 cache is the CACHE at the SQLSession level, which is the cache of a single SQL statement. When operating a database, a SQLSession object needs to be built, and there is a data structure (HashMap) in the object to store cached data. The cache between different SQLSessions does not affect each other
  2. Level 2 cache is Mapper level cache, frankly speaking is an XML file cache, the cache is closed by default, multiple SQLSessions to operate the same Mapper SQL statement, sharing a cache, the cache is cross-SQLSession

Two: level 1 cache

When we are in the SQL query, Mybatis will first to the cache of the SQL statement cache, if the cache already exists, is returned directly from the cache as a result, no longer for the database interaction, when the cache does not exist in the SQL statement cache, will go directly to the database query, get the results, the results will be cached, When the user performs the COMMIT operation (insert, delete, update), the level-1 cache of sqlSession is cleared to avoid dirty reads.

Three: level 2 cache

Level 2 cache is the same as level 1 cache. The first query will put the data into the cache, and subsequent queries will be fetched from the cache. Level 1 cache is sqlSession level, level 2 cache is Mapper level, that is, multiple SQLSessions can share level 2 cache in a mapper. If two Mappers have the same namespace, even if they have different files, the data from their SQL query is maintained in the same level 2 cache.

Four: How to use level 2 cache

1. We need to add the following code to the global configuration file sqlmapconfig. XML:

<! -- Enable level 2 cache --><settings> 
    <setting name="cacheEnabled" value="true"/> 
</settings>
Copy the code

Then enable caching in mapper. XML and add the following configuration

<cache></cache>
Copy the code

The mapper. XML file has an empty label, but it is possible to configure PerpetualCache, which is myBatis’ default caching class. We do not write type to use mybatis default Cache, also can implement Cache interface to customize Cache.

Opened up after the second level cache, also need to be cached pojo implement the Serializable interface, in order to remove the cache data to perform deserialization operations, because the second level cache data storage medium is varied, not only exist in memory, hard drives, possible if we want to take this cache, then you need deserialization. So poJOs in Mybatis implement Serializable interface

In mybatis, you can also configure userCache and flushCache. UserCache is used to disable level-2 caching. UseCache =false is used to disable level-2 caching for select statements. That is, SQL is issued for each query. The default value is true, which means that the SQL uses level 2 caching

<select id="selectUserByUserId" useCache="false" resultType="com.pojo.User" parameterType="int"> 
    select * from user where id=#{id} 
</select>
Copy the code

In this case, the latest SQL data is required for each query. Set this parameter to useCache=false, disable the level 2 cache, and obtain the data directly from the database. In the same namespace of the Mapper, if there are other insert, update, or delete operations, the cache needs to be refreshed. If the cache is not refreshed, dirty reads will occur. Set the flushCache=”true “attribute in the statement configuration. The default value is true, that is, the cache is flushed. If the value is false, the cache is not flushed. If you manually modify the query data in a database table while using caching, dirty reads will occur.

<select id="selectUserByUserId" flushCache="true" useCache="false" resultType="com.pojo.User" parameterType="int"> 
    select * from user where id=#{id} 
</select>
Copy the code

In general, the cache is flushed after the commit operation. FlushCache =true flusher the cache to avoid dirty database reads. So we don’t have to set it, just default

Five: Level 2 cache integer and Redis

Above we introduced mybatis own level 2 cache, but this cache is a single server work, can not achieve distributed cache. So what is distributed caching? Generally the same service will deploy multiple distributed project, if we use mybatis default cache, user access for the first time according to the load balance may access to the server. A, when to second visit, may be access to the server B, then the original cache on server A, we are not, Therefore, the second access still requires direct access to the database, which defeats the purpose of caching, as shown in the following figure:

To solve this problem, it is necessary to find a distributed cache, which is specially used to store the cached data, so that different servers will store the cached data there, and also fetch the cached data from it, as shown in the following figure:

As shown in the figure above, we use a third-party cache framework between several different servers. We put the cache in this third-party framework, and then we can fetch data from the cache no matter how many servers there are. Here we introduce the integration of Mybatis and Redis.

Implementation: POM file:

<dependency> 
    <groupId>org.mybatis.caches</groupId> 
    <artifactId>mybatis-redis</artifactId> 
    <version>1.0.0 beta 2 -</version> 
</dependency>
Copy the code

Configuration file:

<? xml version="1.0" encoding="UTF-8"? > <! DOCTYPE mapper PUBLIC"- / / mybatis.org//DTD Mapper / 3.0 / EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.mapper.IUserMapper"> 
<cache type="org.mybatis.caches.redis.RedisCache" /> 
<select id="findAll" resultType="com.pojo.User" useCache="true"> 
    select * from user 
</select>
Copy the code

redis.properties:

redis.host=localhost 
redis.port=6379 
redis.connectionTimeout=5000 
redis.password= 
redis.database=0
Copy the code

Note: redis. Properties is a fixed file name and cannot be changed

Why is it fixed at this name? Next we look through the source code to find the answer.

RedisCache and the general implementation of Mybatis Cache scheme is similar, nothing more than the implementation of the Cache interface, and the use of jedis operation Cache;

RedisCache is created by mybatis CacheBuilder when mybatis is started. It is simply created by calling RedisCache(String id); In the construction method of RedisCache, RedisConfigu rationBuilder is called to create a RedisConfig object, and RedisConfig is used to create a JedisPool. Now let’s move on to the parseConfiguration() method.

We can see that in the first line of this method there is a path. Call getResourceAsStream() to load the file as an IO stream. Obviously, our configuration file path must be the corresponding one in the coderedisPropertiesFilenameattribute

Let’s see what the value of the redisPropertiesFilename property is

We see that in factredisPropertiesFilenameNo value is specified. Further down, we see a constructor, and in that constructor, we find,redisPropertiesFilenameThe value of the constant is redis.properties, from which we derive the above conclusion.

The end of this article, I hope to help you