Do you know something about mybatis cache?

Time:2021-4-1

Cache implementation

  • L1 cache
  • L2 cache

Case practice

1. First level cache

HashMap local cache based on perpetual cache (mybatis implements the cache interface internally). Its storage scope is session. After session flush or close, all caches in the session will be cleared;

2. L2 cache

The mechanism of the first level cache is the same. By default, it adopts the HashMap storage of perpetual cache. The difference is that the scope of the first level cache is mapper (namespace), and the storage source can be customized, such as ehcache;

For the cache data update mechanism, when the C / R / U / D operation is performed on a scope (first level cache session / second level cache namespace), all the caches in the select in the scope will be cleared by default.

If the second level cache is enabled, first query the data from the second level cache. If the second level cache has data, get the data from the second level cache. If the second level cache does not have data, find whether there is data from the first level cache. If the first level cache does not have data, query the database

3. Limitations of L2 cache

Mybatis two-level cache is not good for fine-grained data level cache. It needs to cache many pieces of data at the same time. For example, it needs to cache the commodity information. Because of the large amount of access to the commodity information query, the user is required to query the latest commodity information every time. At this time, if mybatis is used When a product changes, it can’t refresh the cache information of the product without refreshing the information of other products, because the secondary cache area of mybaits is divided by mapper. When a product changes, it will clear all the cache data of all the product information

4. L1 cache (on by default)

Mybatis provides the first level cache by default, and the cache range is a sqlsession. In the same sqlsession, execute the same SQL query twice, and do not query from the database for the second time.

Principle: the first level cache uses HashMap storage. When mybatis executes the query, it queries from the cache. If there is no query from the database in the cache. If theSqlSession implement clearCache()Submit or add delete modification operations to clear the cache.

The default exists and the observation results are understood

a. Cache existence (session not submitted)

@Test 

public void test01() { 

    SqlSession sqlSession=sqlSessionFactory.openSession();  

    AccountDao accountDao=sqlSession.getMapper(AccountDao.class);  

    Account account=accountDao.queryAccountById(1); 

    System.out.println(account); 

    accountDao.queryAccountById(1);  

} 

The log only prints one SQL

Do you know something about mybatis cache?

b. Refresh cache

When the session is submitted, the cache data is refreshed

@Test 
public void test02() { 
    SqlSession sqlSession=sqlSessionFactory.openSession();  
    AccountDao accountDao=sqlSession.getMapper(AccountDao.class);  
    Account account=accountDao.queryAccountById(1); 
    System.out.println(account); 
    sqlSession.clearCache(); 
    accountDao.queryAccountById(1);  
} 

effect:

Do you know something about mybatis cache?

5. L2 cache

The first level cache is in the same sqlsession, and the second level cache is in the same namespace. Therefore, the second level cache can be used for different sqlsessions with the same namespace.

Usage scenarios

  • Second level cache is recommended for data with high query frequency and low change frequency.
  • For the query requests with more access and the user’s real-time requirements for the query results are not high, the mybatis two-level cache technology can be used to reduce the database access and improve the access speed. Business scenarios such as time-consuming statistical analysis SQL, telephone bill query SQL, etc.

Global file configuration( mybatis.xml )

<setting name="cacheEnabled" value="true"/> 
Mapper.xml  Add: open the secondary cache of the mapper 

<! -- enable the secondary cache of the mapper -- > 

<cache/>

Common attributes of cache tag

<cache  

Eviction = "FIFO" <! -- recovery strategy is FIFO -- > 

Flushinterval = "60000" <! -- auto refresh time 60s -- > 

Size = "512" <! -- cache up to 512 reference objects -- > 

Readonly = "true" / > <! -- read only -- >

explain:

  1. All select statements in the mapping statement file will be cached.
  2. All insert, update and delete statements in the mapping statement file refresh the cache.
  3. The cache is retrieved using the least recently used (LRU) algorithm.
  4. The cache is refreshed at specified intervals
  5. The cache stores 1024 objects

Po objects must support serialization

public class User implements Serializable { 

} 

Close the specific statement cache under mapper

Use usecache: true by default

<select id="findUserByid" parameterType="int" resultType="User"  

useCache="false"> 

    SELECT * FROM user WHERE id=#{id} 

</select> 

Refresh L2 cache

When operating the statement of cud, the secondary cache will be forced to refresh, that is, the default flushcache is set to “true”. If you want to close the statement, you can set it to “flushcache is set to” false “, it is not recommended to close the refresh, because it is easy to get dirty data after the operation is updated, deleted and modified.

L2 cache test:

@Test 

public void test03() { 

    SqlSession sqlSession=sqlSessionFactory.openSession();  

    AccountDao accountDao=sqlSession.getMapper(AccountDao.class);  

    Account account=accountDao.queryAccountById(1); 

    System.out.println(account); 

    sqlSession.close(); 

    SqlSession sqlSession2=sqlSessionFactory.openSession(); 

    AccountDao accountDao2=sqlSession2.getMapper(AccountDao.class);  

    accountDao2.queryAccountById(1); 

    sqlSession.close(); 

} 

effect:

Do you know something about mybatis cache?

extend

Distributed cache ehcache

If there are multiple servers, the distributed cache is not used, and the cached data is stored separately in each server, which is not convenient for system development. So we should use distributed cache to centrally manage the cache data. Therefore, we can use ehcache memcached redis

Mybatis itself is unable to achieve distributed caching, so it should be integrated with distributed caching framework. Ehcache is a pure Java in-process caching framework, which has the characteristics of fast and lean; ehcache is a widely used open source Java distributed cache. Mainly for general cache, Java EE and lightweight container. It has memory and disk storage, cache loader, cache extension, cache exception handler, a gzip cache servlet filter, and supports rest and soap API.

Jar depends on

<dependency> 

    <groupId>net.sf.ehcache</groupId> 

    <artifactId>ehcache-core</artifactId> 

    <version>2.4.4</version> 

</dependency> 

<dependency> 

    <groupId>org.mybatis.caches</groupId> 

    <artifactId>mybatis-ehcache</artifactId> 

    <version>1.0.3</version> 

</dependency> 

Cache interface configuration

<cache type="org.mybatis.caches.ehcache.EhcacheCache"/> 

Add in SRC ehcache.xml (not required, default configuration not used)

<?xml version="1.0" encoding="UTF-8"?> 

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

xsi:noNamespaceSchemaLocation="../bin/ehcache.xsd"> 

<!-- 

Name: the unique identifier of the cache 

Maxelementsinmemory: the maximum number of cached objects in memory 

Maxelementsondisk: the maximum number of cache objects in the disk. If 0, it means infinite 

If the cache is never valid, if it is false, whether it is expired 

Then we should judge according to time to idle seconds and time to live seconds 

Overflow todisk: configure this property. When the number of elements in memory reaches maxelementsinmemory, 

Ehcache writes the element to disk 

Timetoidleseconds: set the allowed idle time of element before invalidation. Only if the element is not permanently valid 

The default value is 0, which means the idle time is infinite 

Timetoliveseconds: set the allowed lifetime of an element before it fails. The maximum time is between creation time and expiration time 

Time. It is only used when the element is not permanently valid. The default value is 0. That is to say, the survival time of the element is infinite 

large 

Diskpersistent: do you want to cache the data during the restart period of the virtual machine 

Diskexpirythreadintervalseconds: the running time interval of disk failure thread. The default is 120 seconds 

diskSpoolBufferSizeMB:这个参数设置 DiskStore(磁盘缓存)的缓存区large小。默认是 

30MB。 Each cache should have its own buffer 

Memorystoreevicationpolicy: when the maxelementsinmemory limit is reached, ehcache will update the 

Specified policy to clean up memory. The default policy is LRU (least recently used). You can set it to FIFO 

Or LFU (less used) 

--> 

<defaultCache overflowToDisk="true" eternal="false"/> 

<diskStore path="D:/cache" /> 

<!-- 

<cache name="sxtcache" overflowToDisk="true" eternal="false" 

timeToIdleSeconds="300" timeToLiveSeconds="600" maxElementsInMemory="1000" 

maxElementsOnDisk="10" diskPersistent="true"  

diskExpiryThreadIntervalSeconds="300" 

diskSpoolBufferSizeMB="100" memoryStoreEvictionPolicy="LRU" /> 

-->

Test:

@Test 

public void test04() { 

    SqlSession sqlSession=sqlSessionFactory.openSession();  

    AccountDao accountDao=sqlSession.getMapper(AccountDao.class);  

    Account account=accountDao.queryAccountById(1); 

    System.out.println(account); 

    sqlSession.close(); 

    SqlSession sqlSession2=sqlSessionFactory.openSession(); 

    AccountDao accountDao2=sqlSession2.getMapper(AccountDao.class);  

    accountDao2.queryAccountById(1); 

    sqlSession.close(); 

} 

effect:

Cache Hit Ratio [com.xxx.dao.AccountDao]:0.5