Redis Java Lettuce驱动框架原理解析

Lettuce是一个高性能基于Java编写的Redis驱动框架,底层集成了Project Reactor提供天然的反应式编程,通信框架集成了Netty使用了非阻塞IO,5.x版本之后融合了JDK1.8的异步编程特性,在保证高性能的同时提供了十分丰富易用的API,5.1版本的新特性如下:

  • 支持Redis的新增命令ZPOPMIN, ZPOPMAX, BZPOPMIN, BZPOPMAX。
  • 支持通过Brave模块跟踪Redis命令执行。
  • 支持Redis Streams。
  • 支持异步的主从连接。
  • 支持异步连接池。
  • 新增命令最多执行一次模式(禁止自动重连)。
  • 全局命令超时设置(对异步和反应式命令也有效)。
  • ......等等

注意一点:Redis的版本至少需要2.6,当然越高越好,API的兼容性比较强大。

引入依赖项:

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

一、连接Redis

单机、哨兵、集群模式下连接Redis需要一个统一的标准去表示连接的细节信息,在Lettuce中这个统一的标准是RedisURI。可以通过三种方式构造一个RedisURI实例:

定制的字符串URI语法:

RedisURI uri = RedisURI.create("redis://localhost/");

使用建造器(RedisURI.Builder):

RedisURI uri = RedisURI.builder().withHost("localhost").withPort(6379).build();

直接通过构造函数实例化:

RedisURI uri = new RedisURI("localhost", 6379, 60, TimeUnit.SECONDS);

二、基本使用

Lettuce使用的时候依赖于四个主要组件:

  • RedisURI:连接信息。
  • RedisClient:Redis客户端,特殊地,集群连接有一个定制的RedisClusterClient。
  • Connection:Redis连接,主要是StatefulConnection或者StatefulRedisConnection的子类,连接的类型主要由连接的具体方式(单机、哨兵、集群、订阅发布等等)选定,比较重要。
  • RedisCommands:Redis命令API接口,基本上覆盖了Redis发行版本的所有命令,提供了同步(sync)、异步(async)、反应式(reative)的调用方式,对于使用者而言,会经常跟RedisCommands系列接口打交道。

一个基本使用例子如下:

RedisURI redisUri = RedisURI.builder()          // <1> 创建单机连接的连接信息
    .withHost("localhost")
    .withPort(6379)
    .withTimeout(Duration.of(10, ChronoUnit.SECONDS))
    .build();
RedisClient redisClient = RedisClient.create(redisUri);  // <2> 创建客户端
StatefulRedisConnection<String, String> connection = redisClient.connect();   // <3> 创建线程安全的连接
RedisCommands<String, String> redisCommands = connection.sync();        // <4> 创建同步命令
SetArgs setArgs = SetArgs.Builder.nx().ex(5);
String result = redisCommands.set("name", "throwable", setArgs);
result = redisCommands.get("name");
System.out.println(result);
// ... 其他操作
connection.close();  // <5> 关闭连接
redisClient.shutdown(); // <6> 关闭客户端

关闭连接一般在应用程序停止之前操作,一个应用程序中的一个Redis驱动实例不需要太多的连接(一般情况下只需要一个连接实例就可以,如果有多个连接的需要可以考虑使用连接池,其实Redis目前处理命令的模块是单线程,在客户端多个连接多线程调用理论上没有效果)。

关闭客户端一般应用程序停止之前操作,如果条件允许的话,基于后开先闭原则,客户端关闭应该在连接关闭之后操作。

三、Lettuce API

  • 同步(sync):RedisCommands。
  • 异步(async):RedisAsyncCommands。
  • 反应式(reactive):RedisReactiveCommands。
RedisURI redisUri = RedisURI.builder()
    .withHost("localhost")
    .withPort(6379)
    .withTimeout(Duration.of(10, ChronoUnit.SECONDS))
    .build();
RedisClient client = RedisClient.create(redisUri);
StatefulRedisConnection<String, String> connection = client.connect();

Redis命令API的具体实现可以直接从StatefulRedisConnection实例获取,见其接口定义:

public interface StatefulRedisConnection<K, V> extends StatefulConnection<K, V> {
  boolean isMulti();
  RedisCommands<K, V> sync();
  RedisAsyncCommands<K, V> async();
  RedisReactiveCommands<K, V> reactive();
} 

值得注意的是,在不指定编码解码器RedisCodec的前提下,RedisClient创建的StatefulRedisConnection实例一般是泛型实例StatefulRedisConnection<String,String>,也就是所有命令API的KEY和VALUE都是String类型,这种使用方式能满足大部分的使用场景。当然,必要的时候可以定制编码解码器RedisCodec<K,V>。

同步API

先构建RedisCommands实例

RedisCommands<String, String> redisCommands= connection.sync();
String pong = redisCommands.ping();
// 返回PONG
System.out.println("pong:" + pong);

SetArgs setArgs = SetArgs.Builder.nx().ex(5);
redisCommands.set("name", "throwable", setArgs);
String value = redisCommands.get("name");
System.out.println("name:" + value);

同步API在所有命令调用之后会立即返回结果。如果熟悉Jedis的话,RedisCommands的用法其实和它相差不大。

异步API

先构建RedisAsyncCommands实例:

RedisAsyncCommands<String, String> redisCommands = connection.async();

基本使用:

RedisAsyncCommands<String, String> redisCommands = connection.async();
RedisFuture<String> redisFuture = redisCommands.ping();
// 返回PONG
System.out.println("pong:" + redisFuture.get());

SetArgs setArgs = SetArgs.Builder.nx().ex(5);
RedisFuture<String> future = redisCommands.set("name", "throwable", setArgs);
System.out.println("name:" + future.get());

RedisAsyncCommands所有方法执行返回结果都是RedisFuture实例,而RedisFuture接口的定义如下:

public interface RedisFuture<V> extends CompletionStage<V>, Future<V> {
  String getError();
  boolean await(long timeout, TimeUnit unit) throws InterruptedException;
}  

也就是,RedisFuture可以无缝使用Future或者JDK1.8中引入的CompletableFuture提供的方法。

反应式API

Lettuce引入的反应式编程框架是Project Reactor,如果没有反应式编程经验可以先自行了解一下Project Reactor。

构建RedisReactiveCommands实例:

RedisReactiveCommands<String, String> redisCommands = connection.reactive();

根据Project Reactor,RedisReactiveCommands的方法如果返回的结果只包含0或1个元素,那么返回值类型是Mono,如果返回的结果包含0到N(N大于0)个元素,那么返回值是Flux。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Java基于redis实现分布式锁代码实例

    为什么会有这个需求: 例如一个简单用户的操作,一个线程去修改用户状态,首先在在内存中读出用户的状态,然后在内存中进行修改,然后在存到数据库中.在单线程中,这是没有问题的.但是在多线程中由于读取,修改,写入是三个操作,不是原子操作(同时成功或失败),因此在多线程中会存在数据的安全性问题. 这个问题的话,就可以用分布式锁在限制程序的并发执行. 实现思路: 就是进来一个先占位,当别的线程进来操作的时候,发现有人占位了,就会放弃或者稍后再试. 占位的实现: 在redis中的setnx命令来实现,redi

  • java操作Redis缓存设置过期时间的方法

    关于Redis的概念和应用本文就不再详解了,说一下怎么在java应用中设置过期时间. 在应用中我们会需要使用redis设置过期时间,比如单点登录中我们需要随机生成一个token作为key,将用户的信息转为json串作为value保存在redis中,通常做法是: //生成token String token = UUID.randomUUID().toString(); //把用户信息写入redis jedisClient.set(REDIS_USER_SESSION_KEY + ":"

  • Springboot2.X集成redis集群(Lettuce)连接的方法

    前提:搭建好redis集群环境,搭建方式请看:https://www.jb51.net/article/143749.htm 1. 新建工程,pom.xml文件中添加redis支持 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> 2

  • Spring boot集成redis lettuce代码实例

    spring boot框架中已经集成了redis,在1.x.x的版本时默认使用的jedis客户端,现在是2.x.x版本默认使用的lettuce客户端 引入依赖 <!-- spring boot redis 缓存引入 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactI

  • SpringBoot 整合 Lettuce Redis的实现方法

    SpringBoot 是为了简化 Spring 应用的创建.运行.调试.部署等一系列问题而诞生的产物,自动装配的特性让我们可以更好的关注业务本身而不是外部的XML配置,我们只需遵循规范,引入相关的依赖就可以轻易的搭建出一个 WEB 工程 Spring Boot 除了支持常见的ORM框架外,更是对常用的中间件提供了非常好封装,随着Spring Boot2.x的到来,支持的组件越来越丰富,也越来越成熟,其中对Redis的支持不仅仅是丰富了它的API,更是替换掉底层Jedis的依赖,取而代之换成了Le

  • SpringBoot整合Lettuce redis过程解析

    首先解释一下Lettuce客户端: Lettuce 和 Jedis 的都是连接Redis Server的客户端程序.Jedis在实现上是直连redis server,多线程环境下非线程安全,除非使用连接池,为每个Jedis实例增加物理连接.Lettuce基于Netty的连接实例(StatefulRedisConnection),可以在多个线程间并发访问,且线程安全,满足多线程环境下的并发访问,同时它是可伸缩的设计,一个连接实例不够的情况也可以按需增加连接实例. 1.添加依赖 <dependenc

  • Java调用Redis集群代码及问题解决

    前言 需要使用以下jar包 Maven项目引用以下配置: <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.6.2</version> </dependency> <dependency> <groupId>redis.clients&l

  • Java实现Redis的集合(set)命令操作

    配置文件请看上篇Java实现redis https://www.jb51.net/article/190922.htm 下面测试redis的集合set的类型,注释里面的代码是linux中redis命令 package com.huadian.set; import com.huadian.redisUntil.JedisPoolUntil; import org.junit.Before; import org.junit.Test; import redis.clients.jedis.Jed

  • 如何使用Java redis实现发送手机验证码功能

    要求: 1.输入手机号,点击发送后随机生成6位数字码,2分钟有效 2.输入验证码,点击验证,返回成功或失败 3.每个手机号每天只能输入3次 代码如下 import redis.clients.jedis.Jedis; import java.util.Random; public class ValidationTest { public static void main(String[] args) { //getValidation("15005076571"); //checkV

  • Redis Java Lettuce驱动框架原理解析

    Lettuce是一个高性能基于Java编写的Redis驱动框架,底层集成了Project Reactor提供天然的反应式编程,通信框架集成了Netty使用了非阻塞IO,5.x版本之后融合了JDK1.8的异步编程特性,在保证高性能的同时提供了十分丰富易用的API,5.1版本的新特性如下: 支持Redis的新增命令ZPOPMIN, ZPOPMAX, BZPOPMIN, BZPOPMAX. 支持通过Brave模块跟踪Redis命令执行. 支持Redis Streams. 支持异步的主从连接. 支持异步

  • redis 使用lettuce 启动内存泄漏错误的解决方案

    redis 使用 lettuce 出现 LEAK: hashedwheelTimer.release() was not called before it's garbage-collected. Enable advanced leak 内存泄漏.其实是内存不够大导致. 找到eclispe 中window->preferences->Java->Installed JRE ,点击右侧的Edit 按钮,在编辑界面中的 "Default VM Arguments "选项

  • springboot2整合redis使用lettuce连接池的方法(解决lettuce连接池无效问题)

    lettuce客户端 Lettuce 和 Jedis 的都是连接Redis Server的客户端程序.Jedis在实现上是直连redis server,多线程环境下非线程安全(即多个线程对一个连接实例操作,是线程不安全的),除非使用连接池,为每个Jedis实例增加物理连接.Lettuce基于Netty的连接实例(StatefulRedisConnection),可以在多个线程间并发访问,且线程安全,满足多线程环境下的并发访问(即多个线程公用一个连接实例,线程安全),同时它是可伸缩的设计,一个连接

  • springboot redis使用lettuce配置多数据源的实现

    目前项目上需要连接两个redis数据源,一个redis数据源是单机模式,一个redis数据源是分片集群模式,这里将具体配置列一下. 项目用的springboot版本为 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.1.RELEASE</ver

  • SpringBoot2.4.2下使用Redis配置Lettuce的示例

    目录 1. Springboot2.4.2下对Redis的基础集成 1.1 maven添加依赖 1.2 添加Redis配置文件 1.3 注册RedisTemplate和StringRedisTemplate的Bean 1.4 编写一个控制器示例进行redis操作 2. 使用redis进行发布订阅 2.1 添加一个发布者的接口 2.2 添加一个发布者的实现类 2.3 添加一个消息监听bean 2.4 添加bean注册 2.5 改写之前的控制器如下 3. 监听key的过期事件 1. Springbo

  • Java异常继承结构解析_动力节点Java学院整理

    Java异常类层次结构图: 异常的英文单词是exception,字面翻译就是"意外.例外"的意思,也就是非正常情况.事实上,异常本质上是程序上的错误,包括程序逻辑错误和系统错误.比如使用空的引用.数组下标越界.内存溢出错误等,这些都是意外的情况,背离我们程序本身的意图.错误在我们编写程序的过程中会经常发生,包括编译期间和运行期间的错误,在编译期间出现的错误有编译器帮助我们一起修正,然而运行期间的错误便不是编译器力所能及了,并且运行期间的错误往往是难以预料的.假若程序在运行期间出现了错误

  • java TreeMap源码解析详解

    java TreeMap源码解析详解 在介绍TreeMap之前,我们来了解一种数据结构:排序二叉树.相信学过数据结构的同学知道,这种结构的数据存储形式在查找的时候效率非常高. 如图所示,这种数据结构是以二叉树为基础的,所有的左孩子的value值都是小于根结点的value值的,所有右孩子的value值都是大于根结点的.这样做的好处在于:如果需要按照键值查找数据元素,只要比较当前结点的value值即可(小于当前结点value值的,往左走,否则往右走),这种方式,每次可以减少一半的操作,所以效率比较高

  • java中使用sax解析xml的解决方法

    在java中,原生解析xml文档的方式有两种,分别是:Dom解析和Sax解析 Dom解析功能强大,可增删改查,操作时会将xml文档以文档对象的方式读取到内存中,因此适用于小文档 Sax解析是从头到尾逐行逐个元素读取内容,修改较为不便,但适用于只读的大文档 本文主要讲解Sax解析,其余放在后面 Sax采用事件驱动的方式解析文档.简单点说,如同在电影院看电影一样,从头到尾看一遍就完了,不能回退(Dom可来来回回读取) 在看电影的过程中,每遇到一个情节,一段泪水,一次擦肩,你都会调动大脑和神经去接收或

  • Redis02 使用Redis数据库(String类型)全面解析

    一 String类型 首先使用启动服务器进程 : redis-server.exe 1. Set 设置Key对应的值为String 类型的value. 例子:向 Redis数据库中插入一条数据类型为String 的记录. 在客户端输入命令: C:\software\redis\64bit>redis-cli.exe -h 127.0.0.1 -p 6379 redis 127.0.0.1:6379> set foo test OK redis 127.0.0.1:6379> get fo

  • Java Thread多线程全面解析

    多线程是java中很重要的知识点,在此小编给大家总结Java Thread多线程,非常有用,希望大家可以掌握哦. 一.线程的生命周期及五种基本状态 关于Java中线程的生命周期,首先看一下下面这张较为经典的图: 上图中基本上囊括了Java中多线程各重要知识点.掌握了上图中的各知识点,Java中的多线程也就基本上掌握了.主要包括: Java线程具有五种基本状态 新建状态(New):当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread(); 就绪状态(Runnab

随机推荐