Caching is usually used to speed up frequently used data in the 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 main class:
@SpringBootApplication
@EnableCaching
Specify the use of Redis cache in the configuration file. If not specified, JVM memory will be used:
Before using Redis for caching, you need to correctly configure the connection information for Redis
# 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 cache manager in the Redis configuration class:
/**
* Declare the cache manager, which will create an aspect and trigger the pointcut of Spring cache annotation 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 retrieve 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 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 |
@Cacheable | If there is cached data, return the cached data; otherwise, execute the method and cache the result |
@CachePut | Cache the result based on the method's request parameters; unlike @Cacheable, it always triggers the actual method invocation |
@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 cache name, 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 empty, it will query from the database and store the result in 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 | Currently called object | #root.target |
targetClass | Class of the currently called object | #root.targetClass |
args | Array of current method parameters | #root.args[0] |
caches | Cache used by the currently called 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 cleared.
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