qinfengge

qinfengge

醉后不知天在水,满船清梦压星河
github

Cache in Spring Boot

Caching is usually used to speed up frequently used data in a database. In most cases, we use Redis to cache hot data from the MySQL database.

EnableCaching
Using caching in Spring Boot is relatively simple. First, add the dependency:

<!-- Cache dependency -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

Enable caching support in the startup class:

@SpringBootApplication
@EnableCaching

Specify the use of Redis cache in the configuration file. If not specified, JVM memory will be used as the cache.
Before using Redis as a cache, the connection information for Redis needs to be correctly configured.

# Caching
spring.cache.type=redis
# Specify prefix
# spring.cache.redis.key-prefix=test
# Specify time-to-live
# spring.cache.redis.time-to-live=1d

Finally, add the @EnableCaching annotation and the cache manager in the Redis configuration class:

/**
 * Declare the cache manager, which will create an aspect and trigger the pointcut of Spring cache annotations based on the annotations and cache status used by the class or method.
 * Based on the annotations used by the class or method and the cache status, this aspect will get data from the cache, add data to the cache, or remove a value from the cache.
 *
 * @return
 */
@Bean
@SuppressWarnings("all")
public CacheManager cacheManager(RedisConnectionFactory factory) {
    RedisSerializer<String> redisSerializer = new StringRedisSerializer();
    Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
    // Solve the problem of query cache conversion exception
    ObjectMapper om = new ObjectMapper();
    om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    jackson2JsonRedisSerializer.setObjectMapper(om);

    // Configure serialization (solve the problem of garbled characters)
    RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
            .entryTtl(Duration.ofDays(1))
            .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
            .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
            .disableCachingNullValues();

    return RedisCacheManager.builder(factory)
            .cacheDefaults(config)
            .build();
}

Cache Annotations

Cache AnnotationExplanation
@EnableCachingEnable support for cache annotations
@CacheConfigUsed to specify unified configuration parameters, so that they do not need to be specified repeatedly in other cache annotations
@CacheableIf there is cached data, return the cached data directly; otherwise, execute the method and cache the result of the method
@CachePutCache the result based on the method's request parameters. Unlike @Cacheable, it always triggers the actual method call
@CacheEvictClear the cache based on certain conditions
@CachingCombine multiple cache annotations

@CacheConfig
This annotation is commonly used to configure unified cache parameters.

// Use this annotation in the controller to specify the name of the cache, similar to a prefix
@CacheConfig(cacheNames = "test")

@Cacheable
This annotation is commonly used in query methods. After using this annotation, it will first check the cache. If the cache is not available, it will query the database and put the query result into the cache.

Mermaid Loading...
// If the global cacheName/value of @CacheConfig is configured, it can be omitted here
@Cacheable(value = "test", key = "methodName")
// @Cacheable supports EL expressions
@Cacheable(key = "methodName + ':' + #p0 + ':' + #p1")
public Result<Object> getSubordinateAddress(String province,String city){}
@Cacheable(value="users", key="#user.id")
public User find(User user) {}

The key attribute supports the following properties:

Attribute NameDescriptionExample
methodNameCurrent method name#root.methodName
methodCurrent method#root.method.name
targetCurrent called object#root.target
targetClassClass of the current called object#root.targetClass
argsArray of current method parameters#root.args[0]
cachesCache used by the current method#root.caches[0].name

@CachePut
This annotation is commonly used to update the cache. It ignores the value in the cache and always executes the method.
Execution order: Call the method -> Get the result -> Update the cache

Mermaid Loading...
@CachePut(value = "myCache", key = "#entity.id")
public void saveEntity(MyEntity entity) {
    repository.save(entity);
}

@CacheEvict
This annotation is used to delete the corresponding cache.

@CacheEvict(value = "myCache", key = "#id")
public void deleteEntityById(Long id) {
    repository.deleteById(id);
}

When using allEntries=true, the key is ignored and all values in the specified cacheName/value are deleted.
You can also use the cacheManager object to delete a specific cache. The following code clears the test cache when it is not empty:

Objects.requireNonNull(restTemplateConfig.cacheManager(null).getCache("test")).clear();

@Caching
This annotation is used to combine multiple cache annotations.

@Caching(
    cacheable = {
        @Cacheable(value = "myCache", key = "#id")
    },
    evict = {
        @CacheEvict(value = "otherCache", key = "#id")
    }
)
public MyEntity getEntityById(Long id) {
    return repository.findById(id).orElse(null);
}

The calling sequence is as follows:

Mermaid Loading...

The Correct Way to Use Cache in Spring Boot Projects!!
Spring Boot Cache Management @EnableCaching, @Cacheable

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.