What do you know about Mybatis cache?

How the cache is implemented

  • Level 1 cache

  • Secondary cache

Case practice

1. Level 1 cache

HashMap local cache based on PerpetualCache (mybatis internally implements the cache interface), and its storage scope is Session. After Session flush or close, all Caches in the Session will be emptied;

2. Secondary cache

The mechanism of the first level cache is the same, the default is also PerpetualCache's HashMap storage, the difference is that its storage scope is Mapper (Namespace), and the storage source can be customized, such as Ehcache;

For the cache data update mechanism, when a C/R/U/D operation is performed in a certain scope (first-level cache Session/second-level cache Namespaces), all caches in select under this scope will be cleared by default.

If the second cache is enabled, first query the data from the second cache, if the second cache has it, get the data from the second cache, if the second cache does not, check whether there is cache data from the first cache, if the first cache does not, query Database .

3. Limitations of secondary cache

Mybatis second-level cache is not good for fine-grained data-level caching. For caching more pieces of data at the same time, such as the following requirements: caching product information, due to the large number of visits to product information queries, but users are required to do it every time Can query the latest product information. At this time, if you use the secondary cache of mybatis, it will not be possible to refresh only the cache information of this product and not the information of other products when a product changes, because the secondary cache area of ​​mybaits is based on mapper. Division, when a product information changes, all the cached data of the product information will be cleared

4. Level 1 cache (enabled by default)

Mybatis provides first level cache by default, and the cache scope is a sqlSession. In the same SqlSession, execute the same sql query twice, and no longer query from the database the second time.

Principle: The first level cache uses Hashmap storage. When mybatis executes a query, it will query from the cache, if there is no query from the database in the cache. If the SqlSession executes clearCache() commit or add delete modification operation, clear the cache.

It exists by default, just understand the observation result

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 a sql

b. Refresh the cache

The cached data is refreshed when the Session is submitted

@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:

5. Secondary cache

The first level cache is in the same sqlSession, and the second level cache is in the same namespace, so different sqlsessions with the same namespace can use the second level cache.

scenes to be used

  • For data with high query frequency and low change frequency, it is recommended to use the secondary cache.

  • For query requests that are accessed frequently and users do not have high requirements for real-time query results, the mybatis secondary cache technology can be used to reduce database access and increase access speed. Business scenarios such as: time-consuming statistical analysis sql, telephone bills Query sql etc.

Global file configuration (mybatis.xml)

<setting name="cacheEnabled" value="true"/> 
Mapper.xml 中加入 :打开该 mapper 的二级缓存 

<!-- 开启该 mapper 的二级缓存 --> 

<cache/>

Common attributes of the cache tag

<cache  

eviction="FIFO" <!--回收策略为先进先出--> 

flushInterval="60000" <!--自动刷新时间 60s--> 

size="512" <!--最多缓存 512 个引用对象--> 

readOnly="true"/> <!--只读--> 

Description:

  1. All select statements in the mapping statement file will be cached.

  2. All insert, update and delete statements in the mapped statement file will refresh the cache.

  3. The cache will use the Least Recently Used (LRU, least recently used) algorithm to recover.

  4. The cache will be refreshed according to the specified time interval.

  5. The cache will store 1024 objects

PO object must support serialization

public class User implements Serializable {
    
     

} 

Turn off the specific statement cache under Mapper

Use useCache: default is true

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

useCache="false"> 

	SELECT * FROM user WHERE id=#{id} 

</select> 

**Refresh the secondary cache**

When operating the CUD statement, the second-level cache is forced to refresh, that is, the default flushCache = "true". If you want to turn off the setting to flushCache="false", it is not recommended to turn off the refresh, because the operation update deletes the modification, and it is easy to get dirty after closing data.

Secondary 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:

Expand

Distributed cache ehcache

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

Mybatis itself cannot achieve distributed caching, so it needs to be integrated with the distributed caching framework. EhCache is a pure Java in-process cache framework, which is fast and capable; Ehcache is a widely used open source Java distributed cache. Mainly for general-purpose cache, Java EE and lightweight containers. It has features such as memory and disk storage, cache loader, cache extension, cache exception handler, a gzip cache servlet filter, and supports REST and SOAP api.

Jar dependency

<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 ehcache.xml under src (not necessary, no default configuration is used)

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

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

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

<!-- 

name:Cache 的唯一标识 

maxElementsInMemory:内存中最大缓存对象数 

maxElementsOnDisk:磁盘中最大缓存对象数,若是 0 表示无穷大 

eternal:Element 是否永远不过期,如果为 true,则缓存的数据始终有效,如果为 false 

那么还要根据 timeToIdleSeconds,timeToLiveSeconds 判断 

overflowToDisk:配置此属性,当内存中 Element 数量达到 maxElementsInMemory 时, 

Ehcache 将会 Element 写到磁盘中 

timeToIdleSeconds:设置 Element 在失效前的允许闲置时间。仅当 element 不是永久有效 

时使用,可选属性,默认值是 0,也就是可闲置时间无穷大 

timeToLiveSeconds:设置 Element 在失效前允许存活时间。最大时间介于创建时间和失效 

时间之间。仅当 element 不是永久有效时使用,默认是 0.,也就是 element 存活时间无穷 

大 

diskPersistent:是否缓存虚拟机重启期数据 

diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是 120 秒 

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

30MB。每个 Cache 都应该有自己的一个缓冲区 

memoryStoreEvictionPolicy:当达到 maxElementsInMemory 限制时,Ehcache 将会根据 

指定的策略去清理内存。默认策略是 LRU(最近最少使用)。你可以设置为 FIFO(先进先 

出)或是 LFU(较少使用) 

--> 

<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
~~~![在这里插入图片描述](https://img-blog.csdnimg.cn/20201222173926321.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3h5eDEyMzIx,size_16,color_FFFFFF,t_70#pic_center)

Guess you like

Origin blog.csdn.net/xyx12321/article/details/111562914