Moment For Technology

Spring Cache integrates Redis and gives it an expiration time!

Posted on Dec. 2, 2022, 12:49 p.m. by Taylor Stein
Category: The back-end Tag: Spring Boot

Small Hub guide:

I don't know if you have set the cache expiration time, let's try?


In the last article, we integrated Redis with SpringBoot and used a RedisTemplate to manipulate cached data, which is flexible.

Today we are going to talk about the Spring Cache annotation that Spring provides for us. Spring supports multiple caching technologies, such as RedisCacheManager, EhCacheCacheManager, and GuavaCacheManager. To use aCacheManager Bean, configure aCacheManager Bean.

After configuration, use the three commonly used annotations to cache data:

  • @Cacheable
  • @CachePut
  • @ CacheEvict.

What do these three notes mean? We'll dissect them in a minute.

1. Configure RedisCacheManager

As mentioned, we need to configure a cache manager before we can use cache annotations to manage the cache. We have integrated Redis in the last article, now we just need to configure RedisCacheManager directly.

  • com.markerhub.config.RedisConfig
/** * Configure a CacheManager to use @cacheable ** public account: MarkerHub */ @Bean public CacheManager cacheManager(RedisTemplateString, Basic configuration Object  template) {/ / RedisCacheConfiguration defaultCacheConfiguration = RedisCacheConfiguration .defaultcacheconFig () // Sets key to String .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(template.getStringSerializer())) // Set value to the Object automatically converted to Json .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(template.getValueSerializer())) // Don't cache null. DisableCachingNullValues () / / cache the data save 1 hour. EntryTtl (Duration. OfHours (1)); / / got a redis cache manager RedisCacheManager RedisCacheManager = RedisCacheManager. RedisCacheManagerBuilder / / redis connection factory FromConnectionFactory (template. GetConnectionFactory ()) / / cache configuration cacheDefaults (defaultCacheConfiguration) / / configuration synchronization to modify or delete put/evict .transactionAware() .build();return redisCacheManager;
}
Copy the code

In the configuration above, most of the code is commented out and we just need to configure it as required. The antisequence strategy extends the parameters of the original RedisTemplate.

  • RedisCacheConfiguration
  • RedisCacheManager

Another important step to remember is to enable Spring Cache caching support. This is as simple as adding an annotation to RedisConfig:

@EnableCaching
Copy the code

Write an example

Now that we have configured RedisCacheManager to help us manage the Cache, we will use the Spring Cache annotations to complete our code tests.

The example below I write may be a little thick, if you don't know for some parameters, suggest you take a look at this article: https://blog.csdn.net/dreamhai/article/details/80642010.

1. @ Cacheable

The tag on a method or class identifies that the method or class supports caching. Spring will cache the return value to Redis after calling the annotated identification method, so that the next time the method is called under the same condition, the return value will be retrieved directly from the cache. This eliminates the need to re-execute the method's business process, improving efficiency.

The three common arguments to @cacheable are as follows:

  • CacheNames Specifies the cache name
  • Key Cache key. Note how to write key
  • Condition caches the conditions to execute and executes when it returns true
@Slf4j
@Service
public class UserServiceImpl implements UserService {

    @Override
    @Cacheable(cacheNames = "cache_user", key="'user_' + #id")
    public User getById(long id) {

        log.info("Check in ---------{}", id);

        User user = new User();
        user.setId(1L);
        user.setUsername("MarkerHub" + id);
        returnuser; }}Copy the code

Then write a specific call:

@RestController
public class UserController {

    @Autowired
    UserService userService;

    @GetMapping("/u/{id}")
    public User index(@PathVariable("id") Long id) {

        User user = userService.getById(id);
        returnuser; }}Copy the code

Under test to access as a result, the access link: http://localhost:8080/u/12,

The console output on the first call:

Come in check the library ---------12Copy the code

On the second access, there is no output, indicating that there is no business method, that is, the result is obtained in redis and returned directly.

Take a look at Redis' visualization tool:

When configuring redis serialization, you must configure the following code, which is described in the Springboot configuration redis.

Jackson2JsonRedisSerializerObject serializer = new Jackson2JsonRedisSerializerObject(Object.class);

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
serializer.setObjectMapper(objectMapper);
Copy the code

If you serialize the value as simple JSON data, this will cause a strong-turn error. Need to pay attention!

2, @ CacheEvict

The tag is on the method, and the cache is removed after the method completes, depending on the condition or key. Common attributes:

  • AllEntries Boolean indicates whether all elements in the cache need to be cleared
  • Key Indicates the key of the cache to be deleted
@Override
@CacheEvict(cacheNames = "cache_user", allEntries = truePublic void update(User User) {// update logic... }Copy the code

Therefore, after the update method executes, all caches in cacheNames="cache_user" will be removed! This is also a very common method. Of course, you can also write to delete a specified cache based on the key:

@Override
@CacheEvict(cacheNames = "cache_user", key = "'user_' + #user.id"Public void update(User User) {// update logic... }Copy the code

3, @ @ CachePut

The annotated method does not check to see if the result of a previous execution exists in the cache before execution. Instead, the method executes each time and stores the result of the execution in the specified cache as a key-value pair.

4, @ Caching

You can annotate multiple annotations on a single annotation with three properties: cacheable, PUT, and evICT, which are used to specify @cacheable, @cachePUT, and @cacheevict, respectively

Expiration time

We've implemented the basic functionality of Spring Cache, incorporating Redis as a RedisCacheManger, but as we know, we can't give the Cache an expiration time when using the @cacheable annotation. But sometimes in some scenarios we do need to give the cache an expiration time!

Automatic expiration is especially important when the cache is inconsistent with the library data, as it is a surefire way to do this. So, how do you give Spring cache an expiration time?

In fact, we do not need to integrate third-party packages, such as Redission, etc., we can configure the expiration time when configuring RedisCacheManager, but the expiration time is for cache.

What does that mean? For example, you use the following note:

@Cacheable(cacheNames = "cache_user", key="'user_' + #id")
Copy the code

We can specify cacheNames as the cache expiration time for cache_user during initialization. Let's first review the initial configuration of the RedisCacheManager.

On the RedisCacheConfiguration above we set a configuration for the expiration time. entryTtl(duration.ofhours (1)), which will keep the cached data for an hour. And through on RedisCacheManager. CacheDefaults (defaultCacheConfiguration) configured. These two lines of code essentially say that all cached data is kept for an hour by default.

We have configured the expiration time of the cache to be one hour compared to the previous one. But it's still a little bit fixed. In general, we want to have different expiration times for different cache_posts, for example, and different expiration times for cache_user. So how do we do this? Can it be implemented in configuration?

The answer is yes, very simple, there is this method in RedisCacheManager:

RedisCacheManagerBuilder withCacheConfiguration(String cacheName, RedisCacheConfiguration cacheConfiguration)
Copy the code

We can configure each cacheName by a different RedisCacheConfiguration, so we have a default cache configuration. With this method in place, we can specify a cache configuration. The difference between each cache configuration is the expiration time. Therefore, let's draw a method to generate the cache configuration, as follows:

RedisCacheConfiguration getCacheConfigurationWithTtl(RedisTemplateString, Object template, long seconds) {

    returnRedisCacheConfiguration. DefaultCacheConfig () // Sets key to String .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(template.getStringSerializer())) // Set value to the Object automatically converted to Json .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(template.getValueSerializer())) // Don't cache null. DisableCachingNullValues () / / cache the data save 1 hour. EntryTtl (Duration. OfSeconds (seconds). }Copy the code

The seconds parameter specifies the cache expiration time. Therefore, we should configure this in the RedisCacheManager:

RedisCacheManager RedisCacheManager = RedisCacheManager. RedisCacheManagerBuilder / / Redis connection factory .fromConnectionFactory(template.getConnectionFactory()) .cacheDefaults(getCacheConfigurationWithTtl(template, 60 * 60)) .withCacheConfiguration("cache_user", getCacheConfigurationWithTtl(template, 60))
                .withCacheConfiguration("cache_post", getCacheConfigurationWithTtl (template, 120)) / / configuration synchronization to modify or delete the put/evict transactionAware (). The build ();return redisCacheManager;
}
Copy the code

Based on the configuration above, we specify cacheName as follows:

  • Cache_user expires in 60 seconds
  • Cache_post expires in 120 seconds
  • Other default expiration time is 1 hour

That's how I recommend you write it!

Many people have other implementations, such as adding #3600 after cacheNames and intercepting the number after # as the expiration time.

@Cacheable(cacheNames = "cache_user#3600", key="'user_' + #id")
Copy the code

If you want to give a key an expiration date, you can write it as:

@Cacheable(cacheNames = "cache_user#3600", key="'user_' + #id + '#3600'")
Copy the code

Actually, it doesn't seem necessary to me. Write in the configuration directly, simple and convenient!

conclusion

Ok, this is the end of today's article, the lower right corner of the point to see before going, ha ha.


Recommended Reading:

Share a set of SpringBoot development blog system source code, as well as complete development documentation! Speed save!

The 100 best Java open source projects to learn on Github, covering a variety of technology stacks!

The latest frequently asked interview questions of 2020 and their answers

Search
About
mo4tech.com (Moment For Technology) is a global community with thousands techies from across the global hang out!Passionate technologists, be it gadget freaks, tech enthusiasts, coders, technopreneurs, or CIOs, you would find them all here.