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 Annotation | Explanation |
---|---|
@EnableCaching | Enable support for cache annotations |
@CacheConfig | Used to specify unified configuration parameters, so that they do not need to be specified repeatedly in other cache annotations |
@Cacheable | If there is cached data, return the cached data directly; otherwise, execute the method and cache the result of the method |
@CachePut | Cache the result based on the method's request parameters. Unlike @Cacheable, it always triggers the actual method call |
@CacheEvict | Clear the cache based on certain conditions |
@Caching | Combine 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.
// 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 Name | Description | Example |
---|---|---|
methodName | Current method name | #root.methodName |
method | Current method | #root.method.name |
target | Current called object | #root.target |
targetClass | Class of the current called object | #root.targetClass |
args | Array of current method parameters | #root.args[0] |
caches | Cache 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
@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:
The Correct Way to Use Cache in Spring Boot Projects!!
Spring Boot Cache Management @EnableCaching, @Cacheable