I. Introduction to Redis integration

Redis is a noSQL database that is frequently used in Java development. Data is stored in memory in the form of key-value pairs. Redis common use scenarios, can do cache, distributed lock, self-increasing sequence, etc., using Redis and the way we use the database is similar, first of all, we need to install a Redis server on our own computer or server, through our Java client in the program integration, Then through the client to complete the redis add, delete, change and check operation. There are many Java client types in Redis, common ones are Jedis, Redission,lettuce, etc., so when we integrate, we can choose to integrate these native clients directly. However, the most common way in springBoot is to integrate Spring-data-Redis, which is a special project provided by Spring to operate Redis. It encapsulates the common operations on Redis, including jedis and Lettuce clients. It’s like adding a facade on top of them.

In this article we will focus on springBoot using common operations for Redis by integrating with Spring-data-Redis.

Since there were no compatibility issues involved, we developed directly on the Feature /MybatisPlus branch.

Second, integration steps

2.1 Adding a Dependency

Add redis required dependencies:

<! -- Integrate redis dependencies -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
Copy the code

Complete pom. XML


      
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>com.lsqingfeng.springboot</groupId>
    <artifactId>springboot-learning</artifactId>
    <version>1.0.0</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.6.2</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

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

        <! -- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
            <scope>provided</scope>
        </dependency>

        <! -- Mybatis - Plus required dependencies -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.1 track of</version>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.5.1 track of</version>
        </dependency>

        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.31</version>
        </dependency>

        <! -- Development hot start -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>

        <! MySQL > select * from 'MySQL';
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <! -- Integrate redis dependencies -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
    </dependencies>
</project>
Copy the code

Spring-boot-starter-data-redis is a starter provided by springBoot itself. We can click to see what dependencies the starter contains:

We can see that there are two core packages spring-data-redis and odactic-core in it, which is why our spring-boot-starter-data-redis default uses the lettuce client.

What if we want to use the Jedis client? We need to exclude the oracle dependency and introduce the related jedis dependency.

So why is it that spring-data-Redis can switch clients freely just by introducing different dependencies? This relates to the automatic configuration principle of springBoot. We can give you a brief explanation.

One of the main reasons springBoot can seamlessly integrate other technologies through various starter frameworks is springBoot’s own automated configuration capabilities. Automated configuration means that springBoot itself has pre-configured the integration classes of some commonly used frameworks. Then from the judgment of the condition of like ConditionOn annotations, to identify whether your project related classes (or configuration), then the relevant configuration initialization.

SpringBoot’s default automatic configuration classes are in the spring-boot-Autoconfigure package, which is imported whenever we build a springBoot project.

This package includes a class called RedisAutoConfiguration, which is the automatic configuration of Redis. In this class will introduce LettuceConnectionConfiguration and JedisConnectionConfiguration two configurations, respectively corresponding to the lettuce and jedis two clients.

And the two classes are used ConditionOn annotations to determine whether to load.

Jedis as follows;

And as a result of our projects are introduced automatic lettuce – core, without relying on introduction of a jedis, so this kind of judgment ChengLiHui LettuceConnectionConfiguration is loaded, and jedis judgements, so will not load. In addition, the oracle configuration takes effect, so the default usage we are using is the lettuce client.

2.2 Adding a Configuration

Then we need to configure the connection redis required account password and other information, here we need to install Redis in advance, to ensure that our native program can connect to our Redis, if you do not know how to install Redis, you can refer to the article: [Linux system installation redis6.0.5] blog.csdn.net/lsqingfeng/…

The general configuration is as follows: Configure redis connection information in the application.yml configuration file

spring:
  redis:
    host: localhost
    port: 6379
    password: 123456
    database: 0
Copy the code

If there are other configurations put together:

server:
  port: 19191

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springboot_learning? serverTimezone=Asia/Shanghai&characterEncoding=utf-8
    username: root
    password: root
  redis:
    host: localhost
    port: 6379
    password: 123456
    database: 0
    lettuce:
      pool:
        max-idle: 16
        max-active: 32
        min-idle: 8
  devtools:
    restart:
      enable: true


third:
  weather:
    url: http://www.baidu.com
    port: 8080
    username: test
    cities:
      - Beijing
      - Shanghai
      - Guangzhou
    list[0]: aaa
    list[1]: bbb
    list[2]: ccc
Copy the code

This way we can operate Redis directly in the project. If you are using a cluster, use the following configuration:

spring:
  redis:
    password: 123456
    cluster:
      nodes: 10.255144.115.: 7001,10.255. 144.115:7002,10.255. 144.115:7003,10.255. 144.115:7004,10.255. 144.115:7005,10.255. 144.115:7006
      max-redirects: 3
Copy the code

But sometimes we want to configure connection pooling for our Redis client. The connection pool is also configured when connecting to mysql. The purpose is to increase the management of data connections, improve the efficiency of access, and ensure the rational use of resources. So how do we configure the connection pool, here we must pay attention to, many online articles, introduced methods may be due to the version is too low, are not particularly accurate. For example, many people use spring.starter-pool configuration, which is incorrect (it is not clear if this is the case in older versions, but it is not the case in springboot-starter-data-redis). The first is the configuration file, because we use the lettuce client, so when configuring, add spring. Redis to add the pool to the configuration, details are as follows;

spring:
  redis:
    host: 10.255144.111.
    port: 6379
    password: 123456
    database: 0
    lettuce:
      pool:
        max-idle: 16
        max-active: 32
        min-idle: 8
Copy the code

If you are using jedis, change the database database to jedis (note that dependencies should also be changed).

But simply adding this to the configuration file does not actually take effect. It is important to note that many students add this section to the configuration file and assume that the connection pool is already configured. In fact, it is not. The most important step is to import a dependency.

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>
Copy the code

After that, the connection pool will take effect. We can make a comparison. This can be seen by observing the value of the RedisTemplate object before and after the guide.

Before importing:

After import:

After the import, our connection pool information has a value, which also confirms our conclusion above.

For configuration information, we can look at the source code, which uses the RedisProperties class to receive redis configuration parameters.

2.3 Use in the project

Once our configuration is ready, we can operate redis in our project, using the RedisTemplate class provided for us in spring-data-Redis. Let’s start with a simple example of inserting a key-value pair (value string).

package com.lsqingfeng.springboot.controller;

import com.lsqingfeng.springboot.base.Result;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/ * * *@className: RedisController
 * @description:
 * @author: sh.Liu
 * @date: "* / 2022-03-08
@RestController
@RequestMapping("redis")
public class RedisController {

    private final RedisTemplate redisTemplate;

    public RedisController(RedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @GetMapping("save")
    public Result save(String key, String value){
        redisTemplate.opsForValue().set(key, value);
        returnResult.success(); }}Copy the code

Third, tool class encapsulation

We have successfully manipulated the Redis server with RedisTemplate in the previous code, such as set a string, we can use:

redisTemplate.opsForValue().set(key, value);
Copy the code

To put a String key-value pair. Redis supports string, List, Hash,set and zset data formats. The common operations of these five data formats are encapsulated in the class RedisTemplate. Strings are opsForValue, lists are listOps, sets are setOps, and so on. You can look at the source code in the RedisTemplate class to get an idea of what it does.

And these functions are in this class, it is not very convenient to use, in all general cases, we are separate encapsulation of a tool class, to abstract some commonly used methods. When operating, operate directly through the utility class.

 
package com.lsqingfeng.springboot.utils;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
 
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
 
/ * * *@className: RedisUtil
 * @description:
 * @author: sh.Liu
 * @date: the 2022-03-09 14:07 * /
@Component
public class RedisUtil {
 
    @Autowired
    private RedisTemplate redisTemplate;
    /** * appends an expiration time ** to a specified key@param key
     * @param time
     * @return* /
    public boolean expire(String key, long time) {
        return redisTemplate.expire(key, time, TimeUnit.SECONDS);
    }
    /** * Obtain expiration time by key **@param key
     * @return* /
    public long getTime(String key) {
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }
    /** * Obtain expiration time by key **@param key
     * @return* /
    public boolean hasKey(String key) {
        return redisTemplate.hasKey(key);
    }
    /** * Removes the expiration time of the specified key **@param key
     * @return* /
    public boolean persist(String key) {
        return redisTemplate.boundValueOps(key).persist();
    }
 
    / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - type String -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
 
    /** * Get the value ** based on key@paramThe key key *@returnValue * /
    public Object get(String key) {
        return key == null ? null : redisTemplate.opsForValue().get(key);
    }
 
    /** * puts the value in cache **@paramThe key key *@paramThe value value *@returnTrue Successful false failed */
    public void set(String key, String value) {
        redisTemplate.opsForValue().set(key, value);
    }
 
    /** * puts the value into the cache and sets the time **@paramThe key key *@paramThe value value *@paramTime Indicates the time (s) -1. The value is unlimited *@returnTrue Successful false failed */
    public void set(String key, String value, long time) {
        if (time > 0) {
            redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
        } else{ redisTemplate.opsForValue().set(key, value); }}/** * Add keys in batches (duplicate keys will overwrite) **@param keyAndValue
     */
    public void batchSet(Map<String, String> keyAndValue) {
        redisTemplate.opsForValue().multiSet(keyAndValue);
    }
 
    /** * Batch add key-value * is added only when there is no key in the map. ** is not added when only one key exists in the map@param keyAndValue
     */
    public void batchSetIfAbsent(Map<String, String> keyAndValue) {
        redisTemplate.opsForValue().multiSetIfAbsent(keyAndValue);
    }
 
    /** * Add or subtract the value of a key-value. * if the key does not exist, a key is created and the number is assigned. ** If the key exists, but the value is not a long integer, an error is reported@param key
     * @param number
     */
    public Long increment(String key, long number) {
        return redisTemplate.opsForValue().increment(key, number);
    }
 
    /** * Add or subtract the value of a key-value. * if the key does not exist, a key is created and the number is assigned. ** If the key exists, but the value is not a pure number, an error is reported@param key
     * @param number
     */
    public Double increment(String key, double number) {
        return redisTemplate.opsForValue().increment(key, number);
    }
 
    / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- the set type -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
 
    /** * Put the data into the set cache **@paramThe key key *@return* /
    public void sSet(String key, String value) {
        redisTemplate.opsForSet().add(key, value);
    }
 
    /** * gets the value ** in the variable@paramThe key key *@return* /
    public Set<Object> members(String key) {
        return redisTemplate.opsForSet().members(key);
    }
 
    /** * randomly fetches the specified number of elements ** in a variable@paramThe key key *@paramThe count value *@return* /
    public void randomMembers(String key, long count) {
        redisTemplate.opsForSet().randomMembers(key, count);
    }
 
    /** * randomly gets the element ** in the variable@paramThe key key *@return* /
    public Object randomMember(String key) {
        return redisTemplate.opsForSet().randomMember(key);
    }
 
    /** * pops the element ** in the variable@paramThe key key *@return* /
    public Object pop(String key) {
        return redisTemplate.opsForSet().pop("setValue");
    }
 
    /** * Gets the length of the value in the variable **@paramThe key key *@return* /
    public long size(String key) {
        return redisTemplate.opsForSet().size(key);
    }
 
    /** * select * from a set based on value@paramThe key key *@paramThe value value *@returnTrue Exists false Does not exist */
    public boolean sHasKey(String key, Object value) {
        return redisTemplate.opsForSet().isMember(key, value);
    }
 
    /** * Checks if the given element is in a variable. * *@paramThe key key *@paramObj element object *@return* /
    public boolean isMember(String key, Object obj) {
        return redisTemplate.opsForSet().isMember(key, obj);
    }
 
    /** * Transfers the element value of the variable to the destination variable. * *@paramThe key key *@paramValue element object *@paramDestKey object *@return* /
    public boolean move(String key, String value, String destKey) {
        return redisTemplate.opsForSet().move(key, value, destKey);
    }
 
    /** * Remove elements ** from set cache@paramThe key key *@paramValues values *@return* /
    public void remove(String key, Object... values) {
        redisTemplate.opsForSet().remove(key, values);
    }
 
    /** * Find the difference between two set variables with the given key **@paramThe key key *@paramDestKey key *@return* /
    public Set<Set> difference(String key, String destKey) {
        return redisTemplate.opsForSet().difference(key, destKey);
    }
 
 
    / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - the hash type -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
 
    /** * join cache **@paramThe key key *@paramThe map key *@return* /
    public void add(String key, Map<String, String> map) {
        redisTemplate.opsForHash().putAll(key, map);
    }
 
    /** * get all hashkeys and value ** under key@paramThe key key *@return* /
    public Map<Object, Object> getHashEntries(String key) {
        return redisTemplate.opsForHash().entries(key);
    }
 
    /** * Verify that there is no specified hashkey ** under the specified key@param key
     * @param hashKey
     * @return* /
    public boolean hashKey(String key, String hashKey) {
        return redisTemplate.opsForHash().hasKey(key, hashKey);
    }
 
    /** * gets the value of the specified key string **@paramThe key key *@paramKey2 key *@return* /
    public String getMapString(String key, String key2) {
        return redisTemplate.opsForHash().get("map1"."key1").toString();
    }
 
    /** * gets the specified value Int **@paramThe key key *@paramKey2 key *@return* /
    public Integer getMapInt(String key, String key2) {
        return (Integer) redisTemplate.opsForHash().get("map1"."key1");
    }
 
    /** * pop up the element and delete **@paramThe key key *@return* /
    public String popValue(String key) {
        return redisTemplate.opsForSet().pop(key).toString();
    }
 
    /** * Removes the HashKey ** of the specified hash@param key
     * @param hashKeys
     * @returnNumber of successful deletes */
    public Long delete(String key, String... hashKeys) {
        return redisTemplate.opsForHash().delete(key, hashKeys);
    }
 
    /** * add or subtract the hashkey **@param key
     * @param hashKey
     * @param number
     * @return* /
    public Long increment(String key, String hashKey, long number) {
        return redisTemplate.opsForHash().increment(key, hashKey, number);
    }
 
    /** * add or subtract the hashkey **@param key
     * @param hashKey
     * @param number
     * @return* /
    public Double increment(String key, String hashKey, Double number) {
        return redisTemplate.opsForHash().increment(key, hashKey, number);
    }
 
    /** * Get all hashkey fields ** under key@param key
     * @return* /
    public Set<Object> hashKeys(String key) {
        return redisTemplate.opsForHash().keys(key);
    }
 
    /** * gets the number of key-value pairs under the specified hash **@param key
     * @return* /
    public Long hashSize(String key) {
        return redisTemplate.opsForHash().size(key);
    }
 
    / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- the list type -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
 
    /** * adds the element value ** to the left of the variable@param key
     * @param value
     * @return* /
    public void leftPush(String key, Object value) {
        redisTemplate.opsForList().leftPush(key, value);
    }
 
    /** * gets the value at the location specified in the collection. * *@param key
     * @param index
     * @return* /
    public Object index(String key, long index) {
        return redisTemplate.opsForList().index("list".1);
    }
 
    /** * gets the value of the specified range. * *@param key
     * @param start
     * @param end
     * @return* /
    public List<Object> range(String key, long start, long end) {
        return redisTemplate.opsForList().range(key, start, end);
    }
 
    /** * puts the last argument value before the first intermediate argument in the specified set, if the intermediate argument value exists. * *@param key
     * @param pivot
     * @param value
     * @return* /
    public void leftPush(String key, String pivot, String value) {
        redisTemplate.opsForList().leftPush(key, pivot, value);
    }
 
    /** * Add parameter elements in batches to the left. * *@param key
     * @param values
     * @return* /
    public void leftPushAll(String key, String... values) {
// redisTemplate.opsForList().leftPushAll(key,"w","x","y");
        redisTemplate.opsForList().leftPushAll(key, values);
    }
 
    /** * adds the element to the rightmost part of the collection. * *@param key
     * @param value
     * @return* /
    public void leftPushAll(String key, String value) {
        redisTemplate.opsForList().rightPush(key, value);
    }
 
    /** * Add parameter elements in batches to the left. * *@param key
     * @param values
     * @return* /
    public void rightPushAll(String key, String... values) {
        //redisTemplate.opsForList().leftPushAll(key,"w","x","y");
        redisTemplate.opsForList().rightPushAll(key, values);
    }
 
    /** * Adds elements to an existing collection. * *@param key
     * @param value
     * @return* /
    public void rightPushIfPresent(String key, Object value) {
        redisTemplate.opsForList().rightPushIfPresent(key, value);
    }
 
    /** * Adds elements to an existing collection. * *@param key
     * @return* /
    public long listLength(String key) {
        return redisTemplate.opsForList().size(key);
    }
 
    /** * removes the first left element in the set. * *@param key
     * @return* /
    public void leftPop(String key) {
        redisTemplate.opsForList().leftPop(key);
    }
 
    /** * Removes the left element from the set while waiting, exits if there is no element after the waiting time. * *@param key
     * @return* /
    public void leftPop(String key, long timeout, TimeUnit unit) {
        redisTemplate.opsForList().leftPop(key, timeout, unit);
    }
 
    /** * removes the element to the right of the set. * *@param key
     * @return* /
    public void rightPop(String key) {
        redisTemplate.opsForList().rightPop(key);
    }
 
    /** * Removes the element on the right of the set while waiting, exits if there is no element after the waiting time. * *@param key
     * @return* /
    public void rightPop(String key, long timeout, TimeUnit unit) { redisTemplate.opsForList().rightPop(key, timeout, unit); }}Copy the code

You can also learn more about RedisTemplate by reading this tool class. To use it, you just need to inject the utility class.

Talk about serialization

The serialization of redis is also something we need to pay attention to when using RedisTemplate. In the example above, we didn’t specify redis serialization, so it used the default serialization. The RedisTemplate class’s generic type is <String,Object>, which means that it supports writing objects, so how the Object is serialized into memory is how it is serialized.

So what is the serialization of Redis? It’s how we store objects in Redis, whether it’s binary data, whether it’s XML, whether it’s JSON. For example, we often store POJO objects in Redis, usually serialized as strings using JSON and stored in Redis.

Redis itself provides the following serialization method:

  • GenericToStringSerializer: any object can be generalized to a string and serialization
  • With JacksonJsonRedisSerializer Jackson2JsonRedisSerializer: in fact is the same
  • JacksonJsonRedisSerializer: serialized object to a json string
  • JdkSerializationRedisSerializer: serialized Java objects
  • StringRedisSerializer: Simple string serialization

If we store String, the default serialization is StringRedisSerializer. If we store is an object, which is used by default JdkSerializationRedisSerializer, is the Jdk serialization way (through the ObjectOutputStream and ObjectInputStream implementation, The disadvantage is that we cannot visually see the contents of the stored objects).

Depending on the data type redis operates on, we can set the corresponding serialization method.

We can see by looking at the source of RedisTemplate, use JdkSerializationRedisSerializer by default. The biggest problem with this serialization is that after the object is stored, it is difficult for us to see the stored content directly, and it is very inconvenient for us to check the problem:

While we are the most frequently used way of object serialization: Jackson2JsonRedisSerializer

The main way to set up the serialization method is to create the RedisTemplate object ourselves in the configuration class and specify the corresponding serialization method during creation.

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {
    @Bean(name = "redisTemplate")
    public RedisTemplate<String, Object> getRedisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
        redisTemplate.setConnectionFactory(factory);
        
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        
        redisTemplate.setKeySerializer(stringRedisSerializer); // The serialization type of key

        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // The method is out of date
// objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance ,
                ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
       
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); // The serialization type of value
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.afterPropertiesSet();
        returnredisTemplate; }}Copy the code

When used in this way, it will be stored according to the json serialization mode we set, and we can easily view the property value when viewing the content in Redis.

Distributed lock

References:

www.cnblogs.com/wangyingshu…

In many scenarios, technologies such as distributed transactions and distributed locks are required to ensure data consistency. Sometimes we need to ensure that a method can only be executed by one thread at a time. In a single-machine (single-process) environment, JAVA provides a lot of concurrency related apis, but not in a multi-machine (multi-process) environment.

For distributed locks, it is best to meet the following requirements

In distributed application clusters, it is guaranteed that the same method can only be executed by one thread on one machine at a time. This lock should be a reentrant lock (to avoid deadlocks). This lock should preferably be a blocking lock with highly available lock acquisition and lock release capabilities

Distributed lock generally has three implementation methods: 1. Database optimistic lock; 2. 2. Distributed lock based on Redis; 3. Distributed lock based on ZooKeeper. This article focuses on the second approach.

A perfect distributed lock must meet the following four conditions: 1. Mutual exclusion. Only one client can hold the lock at any time. 2. Deadlocks do not occur. Even if one client crashes while holding the lock and does not unlock actively, it is guaranteed that subsequent clients can lock it. 3. Fault tolerance. Clients can lock and unlock as long as most Redis nodes are running properly. 4. You must tie the bell. Lock and unlock must be the same client, the client can not unlock the lock added by others.

Redis distributed lock principle:

The implementation of the lock is mainly based on redis SETNX command

SETNX key Value Sets the key value to value if and only if the key does not exist. If the given key already exists, SETNX does nothing. SETNX is short for SET if Not eXists.

** Return value: 1 is returned if the setting is successful. Setting failed, return 0.

The process and matters of using SETNX to complete synchronization lock are as follows:

  1. useSETNXCommand to obtain the lock. If 0 is returned (key already exists, lock already exists), the lock fails to be obtained. Otherwise, the lock succeeds
  2. In order to prevent the program after obtaining the lock exception, causing other threads/processes to callSETNXThe command always returns 0 and enters a deadlock state, requiring a “reasonable” expiration time for the key
  3. Release lock, useDELCommand to delete lock data

This article provides a comprehensive overview of locks in Redis.

Jishuin.proginn.com/p/763bfbd75…

There are many ways to implement Redis locks, which are more or less problematic. Lua script is a relatively perfect solution. The perfect solution is to use RedissionRedLock in the Redission framework. Specific implementation is not given, we can follow this idea to find relevant information. I’ll come back when I have time and energy.