92. Redis ——- Methods and steps for using Lettuce to operate Redis database and demonstrations of three styles of operating Redis database (synchronous sync, asynchronous async, reactive Reactive)

lettuce: English meaning: lettuce
It is a framework for operating redis. Springboot also supports lettuce by default. You can also change it to jedis.
Jedis is also a framework used to operate redis

Lettuce’s core API

  • RedisURI: used to encapsulate the URI information of the Redis server.

  • RedisClient: Represents the Redis client. If you connect to Redis in Cluster mode, use RedisClusterClient.
    Somewhat similar to the redis-cli tool.

  • StatefulConnection: represents the parent interface of the Redis connection. It derives many sub-interfaces to represent different connections.

  • RedisCommands: An interface for executing Redis commands. Its methods cover almost all Redis commands (all the commands introduced earlier are supported)
    Its method name and Redis command name also correspond one-to-one. You will definitely know it at a glance.
    For example, Redis provides the hmset command for operating Hash objects, then RedisCommands supports the hmset() method.
    It derives a RedisPubSubCommands sub-interface for running message publishing/subscribing commands.

Lettuce programming steps:

The general steps for using Lettuce to operate Redis are as follows:

(1) Define RedisURI (somewhat similar to the URL of a database), then use RedisURI as a parameter, create a RedisClient (redis in ordinary stand-alone mode) or RedisClusterClient (redis in cluster mode) object strong>.

(2) Call the connectXxx() method of RedisClient or RedisClusterClient to connect to the Redis server. Depending on the status of the connected Redis server, this method returns the StatefulRedisXxxConnection connection object.

(3) Call the sync(), async() or reactive() method of the StatefulRedisXxxConnection connection object to create a RedisCommands object in synchronous, asynchronous or reactive mode.

sync: synchronization async: asynchronous reactive: reactive

(4) Call RedisCommands to execute Redis commands. This step is the most varied, because RedisCommands can execute all Redis commands.

(5) Closing the resource means closing the connection. When closing resources, follow the convention of “open first and then close”, so first close the connection object with Redis, and then close the RedisClient object.

Redis programming steps: Define URI (specify the connected server) → Create Client → Establish a connection with the server → Create RedisCommands object → Execute commands through RedisCommands object → Close the resource

Build RedisURI:

Lettuce provides the following three ways to build RedisURI:

Method 1: Call the static create() method. This method requires that all connection information be written in the String parameter of the create() method.
This String parameter supports Redis in stand-alone mode, cluster mode, and sentinel mode.

Method 2: Call Builder to build. In this construction method, all information is passed in one by one through the corresponding method of the Builder, so the readability is the best. This is also the method I recommend.

Method 3: Call the constructor to build. This method is the least flexible because it can only pass in 3 constructor parameters. After building the RedisURI in this way, you still need to call its setter method to set it. This method is the worst.

Use the corresponding method of Builder to build RedisURI on the official website
If you use a ladder, you can better access the official website. However, the official website cannot be accessed at the moment. It is under maintenance.

From RedisClient to StatefulConnection connection object

–Used to obtain the connection to the Redis server

Using RedisURI as a parameter, call the create() static method of RedisClient (or RedisClusterClient for clusters) to create a RedisClient (or RedisClusterClient) object.

Call the connectXxx() method corresponding to the RedisClient or RedisClusterClient object according to the Redis running mode to obtain the StatefulConnection connection object.

StatefulConnection provides the following common sub-interfaces:

According to various sub-interfaces, it is used to return various connection objects, such as stand-alone, cluster, master-slave, and sentry.
StatefulRedisConnection: The most basic Redis connection.
StatefulRedisPubSubConnection: Redis connection with message publishing/subscription function.
StatufulRedisMasterSlaveConnection: Redis connection in master-slave mode.
StatefulRedisSentinelConnection: Redis connection in sentinel mode.


**Master-slave mode:** Equivalent to redis having two nodes: the master node and the slave node, which mainly perform operations on the master node. If the master node hangs up, the slave node will be on top. The slave node mainly provides a data backup. function.

**Sentinel mode:** Monitor the master and slave nodes. When there is a problem with the master node, you can find another master node from among the many nodes.

From StatefulConnection to RedisXxxCommands object

Call the following three methods of the StatefulRedisXxxConnection connection object to create a RedisXxxCommands object.

sync(): Creates a RedisCommands object in synchronous mode.
async(): Creates a RedisAsyncCommands object in asynchronous mode.
reactive(): Creates a RedisReactiveCommands object in reactive mode.

RedisCommands functions like the redis-cli.exe tool and is used to execute various Redis commands.
Among them, RedisAsyncCommands is the asynchronous version, and RedisReactiveCommands is the reactive version.

Code demo

1. First create a maven project

Then import lettuce’s dependencies:

The first style: use synchronization to operate the redis database

Create a common class, write a main method, and then operate the redis database synchronously
Run this main method, and then go to the redis database to see if everything is successfully added.

The result of synchronizing the database:

Second style: use asynchronous method to operate redis database

Directly copy the synchronized code above, and then split the main method into multiple methods, which seems to be more in line with the specifications.


The result of asynchronous operation of the redis database is also successful.

The third style: using reactive methods to operate the redis database



operation result

The redsi database also has data, indicating that the reactive database operation is also successful.

Explanation of reactive block method: SpringBoot integrates R2DBC – R2DBC is the reactive version of JDBC

Complete code

Sync

package cn.ljh.app;


import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.ScoredValue;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.sync.RedisCommands;

import java.time.Duration;
import java.util.Map;

//Use Lettuce to operate the redis database synchronously
public class Sync
{<!-- -->
    public static void main(String[] args)
    {<!-- -->

        //1. Define RedisURI
        RedisURI uri = RedisURI.builder()
                .withHost("127.0.0.1")
                .withPort(6379)
                //Select which database among the 16 redis databases
                .withDatabase(0)
                .withPassword(new char[]{<!-- -->'1', '2', '3', '4', '5', '6' })
                .withTimeout(Duration.ofMinutes(5))
                .build();
        //2. Create RedisClient client
        RedisClient redisClient = RedisClient.create(uri);

        //3. Get the connection
        StatefulRedisConnection connect = redisClient.connect();

        //4. Create RedisCommands---------------- Use synchronization to operate the database
        RedisCommands cmd = connect.sync();

        //Perform various operations through redis commands

        //Add a string object
        cmd.set("name","ljh");

        //Add a list object
        cmd.lpush("schools","primary school","middle school","university");

        //Add a set object
        cmd.sadd("items","computer","mouse","wallet");

        //Add zset object, zset has one more score function than set, three methods of adding elements to zset object
        cmd.zadd("test",3.0,"java");
        cmd.zadd("test",3.2,"mysql",3.5,"nosql");
        cmd.zadd("test", ScoredValue.just(2.1,"jsp")
                ,ScoredValue.just(2.2,"vue"));

        //Add a hash object
        cmd.hmset("user", Map.of("name","aaa","age","20","height","170") );


        //Close the resource
        connect.close();
        redisClient.shutdown();

    }
}














ASync

package cn.ljh.app;


import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.ScoredValue;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.async.RedisAsyncCommands;

import java.time.Duration;
import java.util.Map;

//Use Lettuce to operate the redis database asynchronously
public class ASync
{<!-- -->
    //redis client
    private RedisClient redisClient;
    //Connection object
    private StatefulRedisConnection connect;

    //Initialization method
    public void init()
    {<!-- -->
        //1. Define RedisURI
        RedisURI uri = RedisURI.builder()
                .withHost("127.0.0.1")
                .withPort(6379)
                //Select which database among the 16 redis databases
                .withDatabase(1)
                .withPassword(new char[]{<!-- -->'1', '2', '3', '4', '5', '6' })
                .withTimeout(Duration.ofMinutes(5))
                .build();
        //2. Create RedisClient client
        this.redisClient = RedisClient.create(uri);

        //3. Get the connection
        this.connect = redisClient.connect();
    }

    //Commands to operate redis
    public void accessRedis()
    {<!-- -->
        //4. Create RedisAsyncCommands ----------------Use an asynchronous method to operate the database
        RedisAsyncCommands cmd = connect.async();

        //Perform various operations through redis commands

        //Add a string object
        cmd.set("name", "ljh")
                //Function: Because it is asynchronous, wait for the result of the set method to come out in the thenAccept method, and then process the result of the set method. The processing method here is to print
                .thenAccept(System.out::println);

        //Add a list object
        cmd.lpush("schools", "primary school", "middle school", "university").thenAccept(System.out::println);

        //Add a set object
        cmd.sadd("items", "computer", "mouse", "wallet").thenAccept(System.out::println);

        //Add zset object, zset has one more score function than set, three methods of adding elements to zset object
        cmd.zadd("test", 3.0, "java").thenAccept(System.out::println);
        cmd.zadd("test", 3.2, "mysql", 3.5, "nosql").thenAccept(System.out::println);
        cmd.zadd("test", ScoredValue.just(2.1, "jsp")
                , ScoredValue.just(2.2, "vue")).thenAccept(System.out::println);

        //Add a hash object
        cmd.hmset("user", Map.of("name", "aaa", "age", "20", "height", "170") )
                .thenAccept(System.out::println);

    }

    //Close the resource
    public void closeResource()
    {<!-- -->
        connect.close();
        redisClient.shutdown();
    }


    public static void main(String[] args)
    {<!-- -->
        ASync aSync = new ASync();
        aSync.init();
        aSync.accessRedis();
        aSync.closeResource();

    }
}

Reactive

package cn.ljh.app;


import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.ScoredValue;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.async.RedisAsyncCommands;
import io.lettuce.core.api.reactive.RedisReactiveCommands;
import reactor.core.publisher.Mono;

import java.time.Duration;
import java.util.Map;

//Use Lettuce to operate the redis database in a reactive manner
public class Reactive
{<!-- -->
    //redis client
    private RedisClient redisClient;
    //Connection object
    private StatefulRedisConnection connect;

    //Initialization method
    public void init()
    {<!-- -->
        //1. Define RedisURI
        RedisURI uri = RedisURI.builder()
                .withHost("127.0.0.1")
                .withPort(6379)
                //Select which database among the 16 redis databases
                .withDatabase(2)
                .withPassword(new char[]{<!-- -->'1', '2', '3', '4', '5', '6' })
                .withTimeout(Duration.ofMinutes(5))
                .build();
        //2. Create RedisClient client
        this.redisClient = RedisClient.create(uri);

        //3. Get the connection
        this.connect = redisClient.connect();
    }

    //Commands to operate redis
    public void accessRedis()
    {<!-- -->
        /*
         * For reactive APIs, since you want to get the results immediately when testing, you need to use bLock to block the thread and get the results of the reactive method.
         * Otherwise, your program has exited, but the data in Mono or FLux returned by the reactive method has not yet arrived.
         * The data types returned by reactive methods are Mono or Flux.
         * block is equivalent to waiting for the message publisher Mono to publish data. If no data is published, it will keep waiting and blocking, which is equivalent to turning the reactive style into a synchronous data reading method.
         * block(): indicates that the value must be obtained and there must be data;
         *
         * If the front end uses the reactive API in conjunction with WebFLux, the controller can directly return Mono or FLuX, so bLock is not needed.
         * If the front-end uses WEbFLux and the back-end uses reactive api, it is very cool, but if the front-end uses ordinary Spring MVC, it is not ideal.
         */

        //4. Create reactive RedisReactiveCommands ---------------- Use reactive methods to operate the database
        RedisReactiveCommands cmd = connect.reactive();

        //Perform various operations through redis commands

        //Add a string object. The return value is the same as Mono, which can be printed directly.
        System.err.println(cmd.set("name", "ljh").block());

        //Add a list object
        System.err.println(cmd.lpush("schools", "primary school", "middle school", "university").block());

        //Add a set object
        System.err.println(cmd.sadd("items", "computer", "mouse", "wallet").block());

        //Add zset object, zset has one more score function than set, three methods of adding elements to zset object
        System.err.println(cmd.zadd("test", 3.0, "java").block());
        System.err.println(cmd.zadd("test", 3.2, "mysql", 3.5, "nosql").block());
        System.err.println(cmd.zadd("test", ScoredValue.just(2.1, "jsp")
                , ScoredValue.just(2.2, "vue")).block());

        //Add a hash object
        System.err.println(cmd.hmset("user", Map.of("name", "aaa", "age", "20", "height", "170"))
                .block());
    }

    //Close the resource
    public void closeResource()
    {<!-- -->
        connect.close();
        redisClient.shutdown();
    }


    public static void main(String[] args)
    {<!-- -->
        Reactive reactive = new Reactive();
        reactive.init();
        reactive.accessRedis();
        reactive.closeResource();

    }
}

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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>cn.ljh</groupId>
    <artifactId>lettuceqs</artifactId>
    <version>1.0.0</version>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!-- Introduce dependencies of Lettuce, a framework for operating redis -->
        <dependency>
            <groupId>io.lettuce</groupId>
            <artifactId>lettuce-core</artifactId>
            <version>6.1.4.RELEASE</version>
        </dependency>
    </dependencies>

</project>