Overview: the basic operation of spring boot using redis annotations for caching

In spring boot, we can easily use annotations to make redis cache our database. The following are the basic steps:

User table in the database (the primary key id increases automatically)

When creating the springboot project, we selected redis in the non relational database

Project structure:

 

First, add the dependency of the connection pool

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.9.0</version>
</dependency>

Add the redis configuration in the configuration file:

# redis configuration
spring.redis.host=192.168.134.128
spring.redis.port=6379
spring.redis.password=123456
spring.redis.lettuce.pool.min-idle=3
spring.redis.lettuce.pool.max-idle=8

After that, we add the @ EnableCaching annotation on the startup class to indicate that redis cache hosting is enabled

 

Now let's start to transform the service layer

We prepare five methods for testing, adding, deleting, changing and querying, and all queries. The return value of the method cannot be written arbitrarily. Since we want to add a cache, the data added to the cache is operated according to the return value of the method, so the return value of the method must be given as the corresponding object except for the deletion operation

public interface UserService extends IService<User> {
    User saveUser(User user);
    int removeUser(Integer id);
    User updateUser(User user);
    User findById(Integer id);
    List<User> findAll();
}

After that, we add the @ CacheConfig annotation on the service implementation class, and give the cacheNames attribute to distinguish the cache contents in each service. It is generally recommended to use the fully qualified name of this class

Then we come to the specific method

First, we need to add the @ CachePut annotation on the method. This annotation is used for adding and updating methods. The key attribute is to assign a value to the key in redis, and the content is customized. However, in general, the ID of the parameter object is taken as the value for the uniqueness of the key. Here # user.id means the ID attribute of the user in the method description is taken as the value

    @CachePut(key = "#user.id")
    @Override
    public User saveUser(User user) {
        userMapper.insert(user);
        return user;
    }

The next step is to delete the method. We need to add @ CacheEvict annotation on the method. This annotation is generally used to delete the method as a cache. The function of the key attribute is the same as the above

    @CacheEvict(key = "#id")
    @Override
    public int removeUser(Integer id) {
        return userMapper.deleteById(id);
    }

Modify (update) method and use @ CachePut annotation

    @CachePut(key = "#user.id")
    @Override
    public User updateUser(User user) {
        userMapper.updateById(user);
        return user;
    }

Query method, using @ Cacheable annotation

    @Cacheable(key = "#id")
    @Override
    public User findById(Integer id) {
        return userMapper.selectById(id);
    }

The next step is to query all the annotations. Note the key value in the @ Cacheable annotation. We define this value as userAll, but if it is written directly, it will be recognized as a variable. We want this value to be a string type, so we also need to add a layer of single quotation marks, or double quotation marks and escape characters

    @Cacheable(key = "'userAll'")
    @Override
    public List<User> findAll() {
        return userMapper.selectList(new QueryWrapper<User>());
    }

However, at this point, we find that there is a logical problem. Once we perform the operation of adding, deleting and modifying, the userAll in redis will not match the userAll in the database. At this time, we need to remove the userAll in redis. Therefore, when we perform the method of adding, deleting and modifying, we need to use the cache operation of redis several times. At this time, we need to use the @ Caching annotation. Here, we take the method of adding as an example

//  @CachePut(key = "#user.id")
    @Caching(
            put = @CachePut(key = "#user.id"),
            evict = @CacheEvict(key = "'userAll'")
    )
    @Override
    public User saveUser(User user) {
        userMapper.insert(user);
        return user;
    }

The content in @ Caching here means that the userAll key in redis is deleted immediately after adding to redis. The values of the put and evict attributes here are arrays, so we can add multiple add (update) and delete methods (query methods can also use the cacheable attribute)

Similarly, we will also transform other methods (query method is not required). Finally, the method of the service implementation class is as follows:

// @Cacheput (key = "35; user. id") / / specify an id for the added value
    @Caching(// Add multiple cache operations
            put = @CachePut(key = "#user.id"),
            evict = @CacheEvict(key = "'userAll'")
    )
    @Override
    public User saveUser(User user) {
        userMapper.insert(user);
        return user;
    }

    //    @CacheEvict(key = "#id")
    @Caching(
            evict = {@CacheEvict(key = "#id"), @CacheEvict(key = "'userAll'")}
    )
    @Override
    public int removeUser(Integer id) {
        return userMapper.deleteById(id);
    }

    //    @CachePut(key = "#user.id")
    @Caching(
            put = @CachePut(key = "#user.id"),
            evict = @CacheEvict(key = "'userAll'")
    )
    @Override
    public User updateUser(User user) {
        userMapper.updateById(user);
        return user;
    }

    @Cacheable(key = "#id")
    @Override
    public User findById(Integer id) {
        return userMapper.selectById(id);
    }

    @Cacheable(key = "'userAll'")
    @Override
    public List<User> findAll() {
        return userMapper.selectList(new QueryWrapper<User>());
    }

Let's come to the test method. First, test all the queries

    @Test
    public void selectAll(){
        List<User> userList = userService.findAll();
        for (User user : userList) {
            System.out.println("user = " + user);
        }
    }

First query:

We can see that the sql query appears on the console, indicating that this time it is obtained from the query in the database

We checked the contents of redis and found that the message userAll also appeared

Next, perform the second query

We can see that there is no sql output on the console for this query, which indicates that we have successfully configured the redis cache

Next, test the add function

    /**
     * Test add user
     */
    @Test
    public void add(){
        User user = new User();
        user.setName("Tokugawa ");
        userService.saveUser(user);
    }

After execution, we check the database

Successful execution. Next, let's check redis

 

We found that there was only one piece of data, that is, the data with id 10 added this time. The previous userAll information was indeed deleted, indicating that the @ Caching annotation was directly executed

However, we found a problem when viewing redis. We can't understand the data stored in redis at all. This is because when springboot stores the data in redis, because redis can't store java objects, springboot can only serialize the objects into strings and then store them in redis. However, the jdk serialization method is used by default, which is not readable. We generally want it to be converted into json format, At this point, we need to manually configure the serialization mode

First, we import jackson's launcher dependencies

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-json</artifactId>
        </dependency>

Add the following configuration classes to the config package:

@Configuration
public class RedisConfig {

    /**
     * Set cache configuration such as serialization
     *
     * @return
     */
    @Bean
    public RedisCacheConfiguration redisCacheConfiguration() {
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
        // Set the serialization method
        redisCacheConfiguration = redisCacheConfiguration.serializeValuesWith(RedisSerializationContext
                .SerializationPair
                .fromSerializer(RedisSerializer.json()));
        return redisCacheConfiguration;
    }
}

Next, we test the update method

    /**
     *  Test update user
     */
    @Test
    public void update(){
        User user = new User();
        user.setId(10);
        user.setName("a wide field");
        userService.updateUser(user);
    }

We came to redis to check the results

Discover that the stored information has changed into json format, and it is completed

Tags: Redis Spring Boot Cache

Posted by hexguy on Sun, 21 Aug 2022 14:09:46 +0530