Maison  >  Article  >  base de données  >  Comment utiliser la laitue dans Redis

Comment utiliser la laitue dans Redis

WBOY
WBOYavant
2023-05-28 21:51:241648parcourir

1. Résumé

Lettuce est un client Java avancé pour Redis. C'est l'un des clients les plus populaires aux côtés de Jedis. Il est désormais devenu le client Redis par défaut pour la version SpringBoot 2.0.

Par rapport aux anciens Jedis, Lettuce est une étoile montante. Elle est non seulement riche en fonctions, mais offre également de nombreuses nouvelles fonctionnalités, telles que les opérations asynchrones, la programmation réactive, etc., et résout également les problèmes. problème d'insécurité du fil dans la question Jedis.

2. Lettuce

2.1 Utilisation de base

Tout d'abord, créez un projet maven et introduisez le lettuce-core. paquet, vous pouvez l'utiliser. lettuce-core包,就可以使用了。

<dependency>
  <groupId>io.lettuce</groupId>
  <artifactId>lettuce-core</artifactId>
  <version>5.3.1.RELEASE</version>
</dependency>

使用 lettuce 连接 redis,测试是否能正常联通!

public class LettuceMain {

    public static void main(String[] args) {
        RedisURI redisUri = RedisURI.builder()
                .withHost("127.0.0.1")
                .withPort(6379)
                .withPassword("111111")
                .withTimeout(Duration.of(10, ChronoUnit.SECONDS))
                .build();
        RedisClient redisClient = RedisClient.create(redisUri);
        StatefulRedisConnection<String, String> connection = redisClient.connect();
        RedisCommands<String, String> commands = connection.sync();
        System.out.println(commands.ping());
        connection.close();
        redisClient.shutdown();
    }
}

2.2、同步操作

基本上只要是 Jedis 支持的同步命令操作,Lettuce 都支持。

下面,我们以同步操作字符串为例,Lettuce 的 api 操作如下!

public class LettuceSyncMain {

    public static void main(String[] args) {
        RedisURI redisUri = RedisURI.builder()
                .withHost("127.0.0.1").withPort(6379).withPassword("111111")
                .withTimeout(Duration.of(10, ChronoUnit.SECONDS))
                .build();
        RedisClient redisClient = RedisClient.create(redisUri);
        StatefulRedisConnection<String, String> connection = redisClient.connect();
        //获取同步操作命令工具
        RedisCommands<String, String> commands = connection.sync();

        System.out.println("清空数据:"+commands.flushdb());
        System.out.println("判断某个键是否存在:"+commands.exists("username"));
        System.out.println("新增<&#39;username&#39;,&#39;xmr&#39;>的键值对:"+commands.set("username", "xmr"));
        System.out.println("新增<&#39;password&#39;,&#39;password&#39;>的键值对:"+commands.set("password", "123"));
        System.out.println("获取<&#39;password&#39;>键的值:"+commands.get("password"));
        System.out.println("系统中所有的键如下:" + commands.keys("*"));
        System.out.println("删除键password:"+commands.del("password"));
        System.out.println("判断键password是否存在:"+commands.exists("password"));
        System.out.println("设置键username的过期时间为5s:"+commands.expire("username", 5L));
        System.out.println("查看键username的剩余生存时间:"+commands.ttl("username"));
        System.out.println("移除键username的生存时间:"+commands.persist("username"));
        System.out.println("查看键username的剩余生存时间:"+commands.ttl("username"));
        System.out.println("查看键username所存储的值的类型:"+commands.type("username"));

        connection.close();
        redisClient.shutdown();
    }
}

2.3、异步操作

除此之外,Lettuce 还支持异步操作,将上面的操作改成异步处理,结果如下!

public class LettuceASyncMain {

    public static void main(String[] args) throws Exception {
        RedisURI redisUri = RedisURI.builder()
                .withHost("127.0.0.1").withPort(6379).withPassword("111111")
                .withTimeout(Duration.of(10, ChronoUnit.SECONDS))
                .build();
        RedisClient redisClient = RedisClient.create(redisUri);
        StatefulRedisConnection<String, String> connection = redisClient.connect();
        //获取异步操作命令工具
        RedisAsyncCommands<String, String> commands = connection.async();

        System.out.println("清空数据:"+commands.flushdb().get());
        System.out.println("判断某个键是否存在:"+commands.exists("username").get());
        System.out.println("新增<&#39;username&#39;,&#39;xmr&#39;>的键值对:"+commands.set("username", "xmr").get());
        System.out.println("新增<&#39;password&#39;,&#39;password&#39;>的键值对:"+commands.set("password", "123").get());
        System.out.println("获取<&#39;password&#39;>键的值:"+commands.get("password").get());
        System.out.println("系统中所有的键如下:" + commands.keys("*").get());
        System.out.println("删除键password:"+commands.del("password").get());
        System.out.println("判断键password是否存在:"+commands.exists("password").get());
        System.out.println("设置键username的过期时间为5s:"+commands.expire("username", 5L).get());
        System.out.println("查看键username的剩余生存时间:"+commands.ttl("username").get());
        System.out.println("移除键username的生存时间:"+commands.persist("username").get());
        System.out.println("查看键username的剩余生存时间:"+commands.ttl("username").get());
        System.out.println("查看键username所存储的值的类型:"+commands.type("username").get());

        connection.close();
        redisClient.shutdown();
    }
}

2.4、响应式编程

Lettuce 除了支持异步编程以外,还支持响应式编程,Lettuce 引入的响应式编程框架是Project Reactor

public class LettuceMain {

    public static void main(String[] args) throws Exception {
        RedisURI redisUri = RedisURI.builder()
                .withHost("127.0.0.1").withPort(6379).withPassword("111111")
                .withTimeout(Duration.of(10, ChronoUnit.SECONDS))
                .build();
        RedisClient redisClient = RedisClient.create(redisUri);
        StatefulRedisConnection<String, String> connection = redisClient.connect();
        //获取响应式API操作命令工具
        RedisReactiveCommands<String, String> commands = connection.reactive();

        Mono<String> setc = commands.set("name", "mayun");
        System.out.println(setc.block());
        Mono<String> getc = commands.get("name");
        getc.subscribe(System.out::println);
        Flux<String> keys = commands.keys("*");
        keys.subscribe(System.out::println);

        //开启一个事务,先把count设置为1,再将count自增1
        commands.multi().doOnSuccess(r -> {
            commands.set("count", "1").doOnNext(value -> System.out.println("count1:" +  value)).subscribe();
            commands.incr("count").doOnNext(value -> System.out.println("count2:" +  value)).subscribe();
        }).flatMap(s -> commands.exec())
                .doOnNext(transactionResult -> System.out.println("transactionResult:" + transactionResult.wasDiscarded())).subscribe();

        Thread.sleep(1000 * 5);
        connection.close();
        redisClient.shutdown();
    }
}

Utilisez lettuce pour vous connecter à Redis et testez si la connexion peut être normale !

public class LettuceReactiveMain1 {

    public static void main(String[] args) throws Exception {
        RedisURI redisUri = RedisURI.builder()
                .withHost("127.0.0.1").withPort(6379).withPassword("111111")
                .withTimeout(Duration.of(10, ChronoUnit.SECONDS))
                .build();
        RedisClient redisClient = RedisClient.create(redisUri);
        //获取发布订阅操作命令工具
        StatefulRedisPubSubConnection<String, String> pubsubConn = redisClient.connectPubSub();
        pubsubConn.addListener(new RedisPubSubListener<String, String>() {
            @Override
            public void unsubscribed(String channel, long count) {
                System.out.println("[unsubscribed]" + channel);
            }
            @Override
            public void subscribed(String channel, long count) {
                System.out.println("[subscribed]" + channel);
            }
            @Override
            public void punsubscribed(String pattern, long count) {
                System.out.println("[punsubscribed]" + pattern);
            }
            @Override
            public void psubscribed(String pattern, long count) {
                System.out.println("[psubscribed]" + pattern);
            }
            @Override
            public void message(String pattern, String channel, String message) {
                System.out.println("[message]" + pattern + " -> " + channel + " -> " + message);
            }
            @Override
            public void message(String channel, String message) {
                System.out.println("[message]" + channel + " -> " + message);
            }
        });
        RedisPubSubAsyncCommands<String, String> pubsubCmd = pubsubConn.async();
        pubsubCmd.psubscribe("CH");
        pubsubCmd.psubscribe("CH2");
        pubsubCmd.unsubscribe("CH");

        Thread.sleep(100 * 5);
        pubsubConn.close();
        redisClient.shutdown();
    }
}

2.2.Opération synchrone

Fondamentalement, Lettuce prend en charge toutes les opérations de commande synchrones prises en charge par Jedis.

Ci-dessous, nous prenons comme exemple le fonctionnement synchrone des chaînes. Le fonctionnement de l'API de Lettuce est la suivante !

public class LettuceMain {

    public static void main(String[] args) throws Exception {
        ClientResources resources = DefaultClientResources.builder()
                .ioThreadPoolSize(4) //I/O线程数
                .computationThreadPoolSize(4) //任务线程数
                .build();
        RedisURI redisUri = RedisURI.builder()
                .withHost("127.0.0.1").withPort(6379).withPassword("111111")
                .withTimeout(Duration.of(10, ChronoUnit.SECONDS))
                .build();
        ClientOptions options = ClientOptions.builder()
                .autoReconnect(true)//是否自动重连
                .pingBeforeActivateConnection(true)//连接激活之前是否执行PING命令
                .build();
        RedisClient client = RedisClient.create(resources, redisUri);
        client.setOptions(options);
        StatefulRedisConnection<String, String> connection = client.connect();
        RedisCommands<String, String> commands = connection.sync();
        commands.set("name", "关羽");
        System.out.println(commands.get("name"));

        connection.close();
        client.shutdown();
        resources.shutdown();
    }
}

2.3. Opération asynchrone

De plus, Lettuce prend également en charge le fonctionnement asynchrone. Changez l'opération ci-dessus en traitement asynchrone.

public class LettuceMain {

    public static void main(String[] args) throws Exception {
        ClientResources resources = DefaultClientResources.builder()
                .ioThreadPoolSize(4) //I/O线程数
                .computationThreadPoolSize(4) //任务线程数
                .build();
        RedisURI redisUri = RedisURI.builder()
                .withHost("127.0.0.1").withPort(6379).withPassword("111111")
                .withTimeout(Duration.of(10, ChronoUnit.SECONDS))
                .build();
        ClusterClientOptions options = ClusterClientOptions.builder()
                .autoReconnect(true)//是否自动重连
                .pingBeforeActivateConnection(true)//连接激活之前是否执行PING命令
                .validateClusterNodeMembership(true)//是否校验集群节点的成员关系
                .build();
        RedisClusterClient client = RedisClusterClient.create(resources, redisUri);
        client.setOptions(options);
        StatefulRedisClusterConnection<String, String> connection = client.connect();
        RedisAdvancedClusterCommands<String, String> commands = connection.sync();
        commands.set("name", "张飞");
        System.out.println(commands.get("name"));

        connection.close();
        client.shutdown();
        resources.shutdown();
    }
}

2.4, Programmation réactive

En plus de prendre en charge la programmation asynchrone, Lettuce prend également en charge la programmation réactive. Le framework de programmation réactif introduit par Lettuce est le code Project Reactor, si vous n'avez aucune expérience en programmation réactive, vous pouvez d'abord vous renseigner vous-même. <h4></h4>Les cas d'utilisation de la programmation réactive sont les suivants : <p><pre class="brush:java;">public class LettuceMain { public static void main(String[] args) throws Exception { RedisURI redisUri = RedisURI.builder() .withHost(&quot;127.0.0.1&quot;) .withPort(6379) .withPassword(&quot;111111&quot;) .withTimeout(Duration.of(10, ChronoUnit.SECONDS)) .build(); RedisClient client = RedisClient.create(redisUri); //连接池配置 GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig(); poolConfig.setMaxIdle(2); GenericObjectPool&lt;StatefulRedisConnection&lt;String, String&gt;&gt; pool = ConnectionPoolSupport.createGenericObjectPool(client::connect, poolConfig); StatefulRedisConnection&lt;String, String&gt; connection = pool.borrowObject(); RedisCommands&lt;String, String&gt; commands = connection.sync(); commands.set(&quot;name&quot;, &quot;张飞&quot;); System.out.println(commands.get(&quot;name&quot;)); connection.close(); pool.close(); client.shutdown(); } }</pre></p>2.5, publication et abonnement <p></p>Lettuce prend également en charge la publication et l'abonnement de messages Redis, des cas d'implémentation spécifiques Comme suit : <h4><pre class="brush:java;">public class LettuceMain { public static void main(String[] args) throws Exception { //这里只需要配置一个节点的连接信息,不一定需要是主节点的信息,从节点也可以;可以自动发现主从节点 RedisURI uri = RedisURI.builder().withHost(&quot;192.168.31.111&quot;).withPort(6379).withPassword(&quot;123456&quot;).build(); RedisClient client = RedisClient.create(uri); StatefulRedisMasterReplicaConnection&lt;String, String&gt; connection = MasterReplica.connect(client, StringCodec.UTF8, uri); //从节点读取数据 connection.setReadFrom(ReadFrom.REPLICA); RedisCommands&lt;String, String&gt; commands = connection.sync(); commands.set(&quot;name&quot;, &quot;张飞&quot;); System.out.println(commands.get(&quot;name&quot;)); connection.close(); client.shutdown(); } }</pre></h4>2.6. Configuration des ressources et des paramètres du client <p></p>Lettuce Le cadre de communication du client intègre les opérations d'E/S non bloquantes de Netty, les paramètres des ressources du client et les performances, la concurrence et les événements de Lettuce. Le traitement est étroitement lié. Si vous n'êtes pas particulièrement familier avec la configuration des paramètres client, il n'est pas recommandé de modifier les valeurs par défaut de manière intuitive sans expérience, et de simplement conserver la configuration par défaut. <p></p>Dans un environnement hors cluster, le cas de configuration spécifique est le suivant : <p><pre class="brush:java;">public class LettuceMain { public static void main(String[] args) throws Exception { //集群节点 List&lt;RedisURI&gt; uris = new ArrayList(); uris.add(RedisURI.builder().withHost(&quot;192.168.31.111&quot;).withPort(6379).withPassword(&quot;111111&quot;).build()); uris.add(RedisURI.builder().withHost(&quot;192.168.31.112&quot;).withPort(6379).withPassword(&quot;111111&quot;).build()); uris.add(RedisURI.builder().withHost(&quot;192.168.31.113&quot;).withPort(6379).withPassword(&quot;111111&quot;).build()); RedisClient client = RedisClient.create(); StatefulRedisMasterReplicaConnection&lt;String, String&gt; connection = MasterReplica.connect(client, StringCodec.UTF8, uris); //从节点读取数据 connection.setReadFrom(ReadFrom.REPLICA); RedisCommands&lt;String, String&gt; commands = connection.sync(); commands.set(&quot;name&quot;, &quot;张飞&quot;); System.out.println(commands.get(&quot;name&quot;)); connection.close(); client.shutdown(); } }</pre></p> Dans un environnement cluster, le cas de configuration spécifique est le suivant : <h4><pre class="brush:java;">public class LettuceMain { public static void main(String[] args) throws Exception { //集群节点 List&lt;RedisURI&gt; uris = new ArrayList(); uris.add(RedisURI.builder().withSentinel(&quot;192.168.31.111&quot;, 26379).withSentinelMasterId(&quot;mymaster&quot;).withPassword(&quot;123456&quot;).build()); uris.add(RedisURI.builder().withSentinel(&quot;192.168.31.112&quot;, 26379).withSentinelMasterId(&quot;mymaster&quot;).withPassword(&quot;123456&quot;).build()); uris.add(RedisURI.builder().withSentinel(&quot;192.168.31.113&quot;, 26379).withSentinelMasterId(&quot;mymaster&quot;).withPassword(&quot;123456&quot;).build()); RedisClient client = RedisClient.create(); StatefulRedisMasterReplicaConnection&lt;String, String&gt; connection = MasterReplica.connect(client, StringCodec.UTF8, uris); //从节点读取数据 connection.setReadFrom(ReadFrom.REPLICA); RedisCommands&lt;String, String&gt; commands = connection.sync(); commands.set(&quot;name&quot;, &quot;赵云&quot;); System.out.println(commands.get(&quot;name&quot;)); connection.close(); client.shutdown(); } }</pre> </h4>2.7, configuration du pool de threads<p></p>La connexion Lettuce est conçue pour être thread-safe, de sorte qu'une connexion peut être partagée par plusieurs threads en même temps, les connexions lettuce sont automatiquement reconnectées par défaut. L'utilisation d'une seule connexion peut essentiellement répondre aux besoins de l'entreprise. Dans la plupart des cas, il n'est pas nécessaire de configurer un pool de connexions et plusieurs connexions n'amélioreront pas les performances de l'opération. <h4></h4>Mais dans certains scénarios particuliers, tels que les opérations de transaction, l'utilisation d'un pool de connexions serait une meilleure solution. Alors, comment configurer le pool de threads ? <p><pre class="brush:java;">public class LettuceReactiveMain4 { public static void main(String[] args) throws Exception { Set&lt;RedisURI&gt; uris = new HashSet&lt;&gt;(); uris.add(RedisURI.builder().withHost(&quot;192.168.31.111&quot;).withPort(7000).withPassword(&quot;123456&quot;).build()); uris.add(RedisURI.builder().withHost(&quot;192.168.31.112&quot;).withPort(7000).withPassword(&quot;123456&quot;).build()); uris.add(RedisURI.builder().withHost(&quot;192.168.31.113&quot;).withPort(7000).withPassword(&quot;123456&quot;).build()); uris.add(RedisURI.builder().withHost(&quot;192.168.31.114&quot;).withPort(7000).withPassword(&quot;123456&quot;).build()); uris.add(RedisURI.builder().withHost(&quot;192.168.31.115&quot;).withPort(7000).withPassword(&quot;123456&quot;).build()); uris.add(RedisURI.builder().withHost(&quot;192.168.31.116&quot;).withPort(7001).withPassword(&quot;123456&quot;).build()); RedisClusterClient client = RedisClusterClient.create(uris); StatefulRedisClusterConnection&lt;String, String&gt; connection = client.connect(); RedisAdvancedClusterCommands&lt;String, String&gt; commands = connection.sync(); commands.set(&quot;name&quot;, &quot;关羽&quot;); System.out.println(commands.get(&quot;name&quot;)); //选择从节点,只读 NodeSelection&lt;String, String&gt; replicas = commands.replicas(); NodeSelectionCommands&lt;String, String&gt; nodeSelectionCommands = replicas.commands(); Executions&lt;List&lt;String&gt;&gt; keys = nodeSelectionCommands.keys(&quot;*&quot;); keys.forEach(key -&gt; System.out.println(key)); connection.close(); client.shutdown(); } }</pre></p>2.8. Configuration en mode maître-esclave #🎜🎜##🎜🎜#redis utilise généralement le mode de réplication maître-esclave pour construire une architecture à haute disponibilité. plusieurs nœuds esclaves synchronisent automatiquement les dernières données du nœud maître. #🎜🎜##🎜🎜#Lettuce prend en charge la découverte automatique des informations sur les nœuds en mode maître-esclave, puis leur enregistrement local. La configuration spécifique est la suivante : #🎜🎜#rrreee#🎜🎜# Bien sûr, nous pouvons également spécifier manuellement le. nœud de cluster à charger, comme détaillé La configuration est la suivante : #🎜🎜#rrreee#🎜🎜#2.9, Configuration du mode Sentinel#🎜🎜##🎜🎜# Le mode Sentinel est également un point fort de Redis pour atteindre une haute disponibilité du service. une configuration spécifique est implémentée comme suit : #🎜🎜#rrreee# 🎜🎜#2.10, Configuration du mode cluster cluster#🎜🎜##🎜🎜#Le mode cluster cluster est un modèle d'architecture à haute disponibilité introduit plus tard. Il utilise principalement le partitionnement pour stocker les données. . La configuration spécifique est la suivante : #🎜🎜 #rrreee

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer