Redis是一个分布式的缓存数据库,对于Redis数据库来讲,如果想让其正确的实现缓存处理,那么一定要有相应的程序与之匹配。最为常用的Redis客户端组件有两个
Jedis
jedis是一个老牌的Redis访问客户端,在使用jedis的 时候,所有的访问操作都是采用直连的形式进行处理,既:只要进行了访问,那么就立即将访问请求直连到Redis服务器上,由Redis服务器进行资源的分配,同时实现相应的处理操作。但其在Redis5.x版本之后没能提供良好的Stream(Redis5.x的新特性)支持,同时也无法实现安全的连接共享操作。
Lettuce
Lettuce是一个线程安全的Redis客户端,提供同步与异步处理两中操作方案,可以避免阻塞操作带来的性能浪费,同时多个项目可以安全的实现连接共享机制。
本次学习的主要就是Lettuce,需要引入Lettuce的依赖
gradle
compile group: 'io.lettuce', name: 'lettuce-core', version: '5.2.1.RELEASE'
maven
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
连接Redis数据库
在Lettuce组件之中为了方便进行数据库的连接操作,实际上提供有三种的操作模式:
- 直接通过程序的方式进行各种数据的配置
- 进行访问路径的配置构建
- 直接基于字符串进行访问
不管使用的是那种连接的处理模式,都会使用到一个连接的核心类“io.lettuce.RedisURI”,该类不负责进行连接,只负责定义连接的相关信息(主机地址、端口等内容),可以直接使用该类的创建方法进行实例构建:
创建连接:public static RedisURI create(String host,int port);
当获取到了RedisURI的对象实例之后,就可以通过“io.lettuce.core.RedisClient”类实现客户端的连接配置,这个类有两个关键的方法:
- 构建RedisClient:public static RedisClient create(RedisURI,redisURI);
- 获取数据库连接:public StatefulRedisConnection<String,String> connect();
利用RedisURi中的create()方法构建一个连接的路径,随后通过RedisClient进行客户端对象的构建,利用客户端的对象可以创建 若干个redis数据库连接。
package cn.rsthe.lettuce.connecct.connecct;
import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.api.StatefulRedisConnection;
public class RedisServerConnectionDemoA {
/** Redis数据库连接地址*/
private static final String REDIS_HOST = "192.168.2.106";
/** Redis数据库连接端口*/
private static final int REDIS_PORT = 6379;
/** Redis数据库认证信息 */
private static final String REDIS_AUTH = "hellolee";
/** Redis数据库索引 */
private static final int REDIS_DATABASE_INDEX = 0;
public static void main(String[] args) {
//定义连接地址
RedisURI redisURI = RedisURI.create(REDIS_HOST,REDIS_PORT);
//连接的数据库
redisURI.setDatabase(REDIS_DATABASE_INDEX);
//认证信息
redisURI.setPassword(REDIS_AUTH);
//创建RedisClient实例
RedisClient redisClient = RedisClient.create(redisURI);
//创建连接
StatefulRedisConnection<String,String> connection = redisClient.connect();
System.out.println("【连接实例】"+connection);
//关闭连接
connection.close();
//关闭Redis客户端
redisClient.shutdown();
}
}
结果:
当前的数据库处理操作实际上和传统的JDBC配置形式是非常接近的,利用各种配置信息创建各种的地址个连接对象,最终实现相关的数据库处理操作。
除了可以使用RedisURI进行手工构建之外,也可以直接通过RedisURI.Builder进行连接的构建处理。
在RedisURI类之中提供有一个Builder构建内部类,在这个类中提供有一些操作方法,可以用于进行RedisURI的创建:
- 获取RedisURL.Builder实例:public static RedisUrl.Builder redis(String host);
- 获取RedisURL.Builder实例:public static RedisUrl.Builder redis(String host,int port);
- 配置认证信息:public RedisURI.Builder withPassWord(String password);
- 配置端口:public RedisURI.Builder withPort(int port);
- 配置数据库:public RedisURI.Builder withDataBase(int dataBase);
- 配置延迟时间:public RedisURI.Builder withTimeout(Duration timeout);
- 创建RedisURI实例:public RedisURI build();
package cn.rsthe.lettuce.connecct.connecct;
import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.api.StatefulRedisConnection;
public class RedisServerConnectionDemoB {
/** Redis数据库连接地址*/
private static final String REDIS_HOST = "192.168.2.106";
/** Redis数据库连接端口*/
private static final int REDIS_PORT = 6379;
/** Redis数据库认证信息 */
private static final String REDIS_AUTH = "hellolee";
/** Redis数据库索引 */
private static final int REDIS_DATABASE_INDEX = 0;
public static void main(String[] args) {
//定义连接地址
RedisURI redisURI = RedisURI.Builder.redis(REDIS_HOST).withPort(REDIS_PORT)
.withPassword(REDIS_AUTH).withDatabase(REDIS_DATABASE_INDEX).build();
RedisClient redisClient = RedisClient.create(redisURI);
StatefulRedisConnection connection = redisClient.connect();
System.out.println("【连接实例】"+connection);
//关闭连接
connection.close();
//关闭Redis客户端
redisClient.shutdown();
}
}
结果:
前面的两种创建连接的方案都属于传统的的程序连接构建,为了充分发挥出字符串操作的优势,所有在RedisURI类提供一个可以使用字符串进行RedisURI实例创建的方法:“public static RedisURI create(String uri);”
定义连接信息:“redis://认证信息@连接地址:端口/数据库”
package cn.rsthe.lettuce.connecct.connecct;
import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.api.StatefulRedisConnection;
public class RedisServerConnectionDemoC {
/** Redis数据库连接地址 */
private static final String REDIS_ADDRESS = "redis://hellolee@192.168.2.106:6379/0";
public static void main(String[] args) {
//定义连接地址
RedisURI redisURI = RedisURI.create(REDIS_ADDRESS);
RedisClient redisClient = RedisClient.create(redisURI);
StatefulRedisConnection connection = redisClient.connect();
System.out.println("【连接实例】"+connection);
//关闭连接
connection.close();
//关闭Redis客户端
redisClient.shutdown();
}
}
结果:
Lettuce的基本操作
当获取了Redis的连接之后,最为重要的目的是要进行Redis数据库的操作,而使用Lettuce组件有一个最大的特点在于,其可以创建同步操作也可以创建异步操作。如果要进行数据库的操作则一定要创建Redis的命令对象实例,在Redis里面有两类命令处理对象,都是通过“io.lettuce.core.api.StatefulRedisConnection”接口创建的,该接口有几个重要的方法:
- 同步命令:public RedisCommands<K,V> sync();
- 异步命令:public RedisAsyncCommands<K,V> async();
- 创建响应命令:public RedisReactiveCommands<K,V> reactive();
一、创建一个Redis数据库连接工具类
package cn.rsthe.lettuce.util;
import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.api.StatefulRedisConnection;
public class RedisConnectionUtil {
/**Redis数据库连接地址*/
private static final String REDIS_ADDRESS = "redis://hellolee@192.168.2.106:6379/0";
private static final RedisURI REDIS_URI = RedisURI.create(REDIS_ADDRESS);
private static final RedisClient REDIS_CLIENT = RedisClient.create(REDIS_URI);
private static final ThreadLocal<StatefulRedisConnection> REDIS_CONNECTION_THREAD_LOCAL = new ThreadLocal<>();
public static StatefulRedisConnection getConnection(){
StatefulRedisConnection<String,String> connection = REDIS_CLIENT.connect();
if (connection == null){
connection = build();
REDIS_CONNECTION_THREAD_LOCAL.set(connection);
}
return connection;
}
public static void close(){
StatefulRedisConnection connection = REDIS_CONNECTION_THREAD_LOCAL.get();
if (connection != null){
connection.close();
REDIS_CONNECTION_THREAD_LOCAL.remove();
}
}
private static StatefulRedisConnection build(){
StatefulRedisConnection<String ,String > connection = REDIS_CLIENT.connect();
return connection;
}
}
二、(1)创建同步操作命令
package cn.rsthe.lettuce.base;
import cn.rsthe.lettuce.util.RedisConnectionUtil;
import io.lettuce.core.api.sync.RedisCommands;
public class SyncCommandDemo {
public static void main(String[] args) {
//创建一个同步操作命令
RedisCommands commands = RedisConnectionUtil.getConnection().sync();
//向Redis之中保存数据
commands.set("lee","HelloRedis");
System.out.println("【获取指定Key的数据】"+commands.get("lee"));
//关闭连接
RedisConnectionUtil.close();
}
}
执行结果:
二、(2)创建异步操作命令
package cn.rsthe.lettuce.base;
import cn.rsthe.lettuce.util.RedisConnectionUtil;
import io.lettuce.core.RedisFuture;
import io.lettuce.core.api.async.RedisAsyncCommands;
import java.util.concurrent.TimeUnit;
public class ASyncCommandDemo {
public static void main(String[] args) throws Exception {
//创建一个同步操作命令
RedisAsyncCommands commands = RedisConnectionUtil.getConnection().async();
//向Redis之中保存数据
commands.setex("lee",3,"HelloRedis");
//延迟一秒
TimeUnit.SECONDS.sleep(1);
RedisFuture future1 = commands.get("lee");
System.out.println("【延迟一秒获取数据】"+future1.get());
//延迟三秒
TimeUnit.SECONDS.sleep(3);
RedisFuture future3 = commands.get("lee");
System.out.println("【延迟一秒获取数据】"+future3.get());
//关闭连接
RedisConnectionUtil.close();
}
}
执行结果:
其余的操作命令与Redis服务器上的操作都是一致的。
查询所有的Key
public class ASyncCommandDemo {
public static void main(String[] args) throws Exception {
//创建一个同步操作命令
RedisAsyncCommands commands = RedisConnectionUtil.getConnection().async();
commands.set("lee","HelloRedis");
System.out.println("【所有的key】"+commands.keys("*").get());
//关闭连接
RedisConnectionUtil.close();
}
}
flushdb、flushall操作
public class ASyncCommandDemo {
public static void main(String[] args) throws Exception {
//创建一个同步操作命令
RedisAsyncCommands commands = RedisConnectionUtil.getConnection().async();
//清空当前所在数据库
commands.flushdb();
//清空整个Redis数据库
commands.flushall();
System.out.println("【所有的key】"+commands.keys("*").get());
//关闭连接
RedisConnectionUtil.close();
}
}
操作Hash数据
public class AsyncHashCommandDemo {
public static void main(String[] args) throws Exception {
//创建一个同步操作命令
RedisAsyncCommands commands = RedisConnectionUtil.getConnection().async();
//向Redis之中保存数据
commands.hset("hello-shu","name","ShuXiaoL").get();
Map<String,String> map = new HashMap<>(3);
map.put("age",String.valueOf(18));
map.put("salary",String.valueOf(999.9));
commands.hmset("hello-shu",map).get();
System.out.println("【获取Hash数据 —— 一个Key】"+commands.hget("hello-shu","name").get());
Map<String,String > getMap = new HashMap<>(3);
getMap.put("age","age");
getMap.put("salary","salary");
System.out.println("【获取Hash数据 —— 多个Key】"+commands.hmget("hello-shu","name","age","salary").get());
System.out.println("【获取Hash数据 —— 设置重复数据】"+commands.hsetnx("hello-shu","salary",String.valueOf(1999.9)).get());
System.out.println("【获取Hash数据 —— 删除数据】"+commands.hdel("hello-shu","name").get());
System.out.println("【获取Hash数据 —— “name”删除后】"+commands.hget("hello-shu","name").get());
System.out.println("【获取Hash数据 —— 获取所有数据(Value)】"+commands.hvals("hello-shu").get());
System.out.println("【获取Hash数据 —— 获取所有数据(Key=Value)】"+commands.hgetall("hello-shu").get());
//关闭连接
RedisConnectionUtil.close();
}
}
执行结果:
操作list数据
public class AsyncListCommandDemo {
public static void main(String[] args) throws Exception {
//创建一个同步操作命令
RedisAsyncCommands commands = RedisConnectionUtil.getConnection().async();
//向队列左边添加数据
System.out.println("【获取List数据 —— 左边保存后个数】" + commands.lpush("queue", "hello-a", "hello-b", "hello-c", "hello-d").get());
//向队列右边添加数据
System.out.println("【获取List数据 —— 右边保存后的个数】" + commands.rpush("queue", "word_1", "word_2", "word_3", "word_4").get());
System.out.println("【获取List数据 —— 内容】" + commands.lrange("queue", 0, -1).get());
System.out.println("【获取List数据 —— 长度】" + commands.llen("queue").get());
long size = (long) commands.llen("queue").get();
for (long x = 0; x < size; x++) {
System.out.println("【List数据左边弹出】" + commands.lpop("queue").get());
//System.out.println("【List数据右边弹出】" + commands.rpop("queue").get());
}
//关闭连接
RedisConnectionUtil.close();
}
}
执行结果:
操作Set数据
public class AsyncSetCommandDemo {
public static void main(String[] args) throws Exception {
//创建一个同步操作命令
RedisAsyncCommands commands = RedisConnectionUtil.getConnection().async();
System.out.println("【获取Set数据 —— A集合保存后个数】" + commands.sadd("set-a","a","b","c","d","e","f","g","a","f").get());
System.out.println("【获取Set数据 —— B集合保存后个数】" + commands.sadd("set-b","1","t","1","a","c","d","e","k","2").get());
System.out.println("【获取Set数据 —— 查看A集合数据】" + commands.smembers("set-a").get());
System.out.println("【获取Set数据 —— 查看B集合数据】" + commands.smembers("set-b").get());
System.out.println("【获取Set数据 —— 差集运算】" + commands.sdiff("set-a","set-b").get());
System.out.println("【获取Set数据 —— 交集运算】" + commands.sinter("set-a","set-b").get());
System.out.println("【获取Set数据 —— 并集运算】" + commands.sunion("set-a","set-b").get());
//关闭连接
RedisConnectionUtil.close();
}
}
执行结果:
操作ZSet数据
public class AsyncZSetCommandDemo {
public static void main(String[] args) throws Exception {
//创建一个同步操作命令
RedisAsyncCommands commands = RedisConnectionUtil.getConnection().async();
commands.zadd("hotword",12.0,"HelloWorld");
commands.zadd("hotword",22.0,"Java");
commands.zadd("hotword",1.0,"C");
commands.zadd("hotword",2.0,"C++");
System.out.println("【获取ZSet数据 —— 升序排列】" + commands.zrange("hotword",0,-1).get());
System.out.println("【获取ZSet数据 —— 降序排列】" + commands.zrevrange("hotword",0,-1).get());
System.out.println("=======================================================================");
System.out.println("【获取ZSet数据 —— 评分成绩降序排列】" + commands.zrangeWithScores("hotword",0,-1).get());
System.out.println("【获取ZSet数据 —— 评分成绩升序排列】" + commands.zrevrangeWithScores("hotword",0,-1).get());
//关闭连接
RedisConnectionUtil.close();
}
}
执行结果:
操作GEO数据
public class AsyncGEOCommandDemo {
public static void main(String[] args) throws Exception {
//创建一个同步操作命令
RedisAsyncCommands commands = RedisConnectionUtil.getConnection().async();
commands.geoadd("me",125.5847949057,34.9957012967,"mywork");
commands.geoadd("me",125.5484640337,34.9326152290,"myhome");
commands.geoadd("me",124.9216173050,34.9799318876,"mylove");
System.out.println("【获取GEO数据】" + commands.geopos("me","mywork","myhome","mylove").get());
System.out.println("【获取GEO数据 —— 工作到家的距离】" + commands.geodist("me","myhome","mywork", GeoArgs.Unit.km).get()+" Km");
//关闭连接
RedisConnectionUtil.close();
}
}
执行结果: