Redis学习笔记Day01-Redis入门

news2024/11/28 22:53:07

声明:本博客部分内容是从终极SpringBoot讲义摘抄的,文字是OCR识别出来的,有可能存在识别错误的可能,如有错误,请大胆指正,我马上修改!

目录

  • 0.官方参考手册API
  • 1.连接命令
  • 2.key相关命令
  • 3.String命令
  • 4.List命令
  • 5.Set命令
  • 6.ZSet命令
  • 7.Hash相关命令
  • 8.事务相关命令
  • 9.Java代码运行示例
    • 9.1Redis同步请求代码
    • 9.2Redis异步请求代码
    • 9.3Redis反应式请求代码
  • 10.订阅发布的Redis的Java代码演示
    • 1.Subscriber.java
    • 2.subscriber2.java
    • 3.Publisher.java
  • 11.杂碎的Redis笔记

在介绍 Redis 的使用之前,先简单介绍一下Redis 的数据存储知识。Redis 使用key-value 结构来保存数据,其中 value 支持如下 5 种数据类型。

  • Sting:最基本的数据类型,可保存任何数据。
  • Hash:是key-value 集合(类似于 Java 的 Map),key 和value 都是String 类型的数据。这
    种类型主要用于保存对象。
  • List: 元素是String 类型的有序集合,集合中的元素可以重复。
  • Set: 元素是 String 类型的无序集合,集合中的元素不能重复。
  • ZSet:元素是 string 类型的有序集合,集合中的元素不能重复。

Redis 为不同数据类型提供了不同的操作命令,因此对于特定类型的数据需要使用对应类型的命令执行操作。
下面简单介绍一些 Redis 的常用命令。

0.官方参考手册API

👉:🔗Spring Data Redis 官方API参考手册
👉:🔗Lettuce 6.2.5.RELEASE API官方API参考手册

1.连接命令

auth 【用户名】 【密码】
这里用户名可以省略,假如我的密码是123456可以直接
auth 123456

在这里插入图片描述

2.key相关命令

与key 相关的常用命令如下。

  • DEL key:刪除key 対的 key-value 対。
  • DUMP key:导出key 对应的值。
  • EXISTS key: 判断key 是否存在。
  • EXPIRE key seconds:设置key对应的key-value 对经过 seconds 秒后过期。
  • EXPIREAT key timestamp:设置key 对应的key-value 对到timestamp 时过期。
  • PEXPIRE key milliseconds: 设置 key 対的 key-value 对经过 milliseconds 毫秒后辻期。
  • PEXPIREAT key milliseconds-timestamp: 设置 key 对应的 key-value 对到
    milliseconds-timestamp 时过期。
  • KEYS pattern: 返回匹配 pattern 的所有 key.
  • MOVE key db:将指定 key 移动到db 数据库中。
  • PERSIST key:删除key 的过期时间,key 将持久保持。
  • PTTL key: 以毫秒为单位返回指定 key剩余的过期时间。
  • TTL key:以秒为单位返回指定key剩余的过期时问。
  • RANDOMKEY:从当前数据库返回一个随机的 key。
  • RENAME key newkey: 将 key 重命名 newkey。
  • RENAMENX key newkey: 相当手安全版的 RENAME, 当 newkey 不存在オ能重命名
  • TYPE key:返回指定 key 存储的数据类型。
    运行示例
    在这里插入图片描述
    在这里插入图片描述

3.String命令

正如前面所言,Redis 内不同数据类型提供了不同的操作命令,当 value 是 String 类型時,需要使用与 string 相关的命令进行操作。与 string 相关的常用命令如下。

  • SET key value: 设置 key-value 対。
  • GET key:返回指定key 对应的 value。
  • GETRANGE key start end: 获取指定 key 対的 value 中心 start 到 end 的子串。
  • GETSET key value: 指定 key 设置新的 value,非返回原来的 value。
  • MGET key [key .]:返回一个(或多个)指定key 对应的 value。
  • SETEX key seconds value:设置key-value 对,并设置过期时间为 seconds 秒。
  • SETNX key value: SET 的安全版本,只有当key 不存在时才能设置该key-value 对。
  • SETRANGE key offset value: 设置和覆盖指定key对应的 value,从原有 value 的 offset 个字符开始;如果key 不存在,则将前 offset 个字符设为空 (\N0000)。
  • STRLEN key:获取 key对应的value 的字符串长度。
  • MSET key value rkey value…]:设置多个key value对。
  • MSETNX key value Tkey value…]: MSET 的安全版本,仅当所有key 都不存在时才能设置 成功。
  • PSETEX key milliseconds value: SETEX 的毫秒版本,过期时间以毫秒计算。
  • INCR key:将指定 key 中存储的整数值加 1。
  • INCRBY key increment. 将指定key 中存修的整数値増加、inorement 整数值。
  • INCRBYFLOAT key increment. INCRBY 的平点数版木,incremcnt 可以是小数。
  • DECR Key:将指定 koy 中存储的整数值减1。
  • DECRBY key decrement。将指定key 中存储的整数值少decrement整数值。
  • APPEND key value 在指定key对应的字符串后追加新的value内容

在这里插入图片描述
在这里插入图片描述

4.List命令

List代表有序的集合,可通过命令为List添加或删除元素,List最多可包含232-1个元素。实际上,Redis的List也具有队列的性质,因此它包含了LPUSH LPOP RPUSH RPOP等命令,其中LPUSH LPOP表示从List的左边(队列头部)压入弹出元素;RPUSH RPOP表示从List的右边(队列尾部)压入弹出元素。
与List相关的常用命令如下。
➢ LINDEX key index:获取key对应的List的index处的元素。
➢ LINSERT key BEFORE|AFTER pivot value:在key对应的List的pivot元素之前或之后插入新的value元素。
➢ LLEN key:返回key对应的List的长度。
➢ LPOP key:弹出并返回key对应的List的第一个元素。
➢ LPUSH key value [value…]:向key对应的List的左边(队列头部)添加一个或多个元素。
➢ LPUSHX key value:LPUSH的安全版本,仅当key对应的List存在时有效。
➢ LRANGE key start stop:获取key对应的List中从start到stop范围内的元素。
➢ LREM key count value:从key对应的value中删除count个value元素。如果count大于0,则从左向右删除count个元素;如果count小于0,则从右向左删除count个元素;如果count等于0,则删除所有元素。
➢ LSET key index value:将key对应的List的index处的元素改为value。
➢ LTRIM key start stop:修剪List,只保留key对应的List中从start到stop之间的元素。
➢ RPOP key:弹出并返回key对应的List的最后一个元素。
➢ RPOPLPUSH source destination:弹出source的最后一个元素,添加到destination的左边(队列头部),并返回该元素。
➢ RPUSH key value [value…]:向key对应的List的右边(队列尾部)添加一个或多个元素。
➢ RPUSHX key value:RPUSH的安全版本,仅当key对应的List存在时有效。
➢ BLPOP key [key…] timeout:LPOP的阻塞版本。弹出并返回多个List的第一个元素,如果某个List没有元素,该命令会阻塞进
程,直到所有List都有元素弹出或超时。该命令的B代表Block。
➢ BRPOP key [key] timeout:RPOP的阻塞版本。弹出并返回多个List的最后一个元素,如果某个List没有元素,该命令会阻塞进
程,直到所有List都有元素弹出或超时。
➢ BRPOPLPUSH source destination timeout:RPOPLPUSH的阻塞版本,如果source中没有元素,该命令会阻塞进程,直到source有元
素弹出或超时。
在这里插入图片描述
在这里插入图片描述

5.Set命令

Set代表无序元素不能重复的集合,因此Set中的元素都是唯一的。Set最多可包含232-1个元素。Set底层其实是通过Hash表实现的,
因此它的删除查找的复杂度都是O(1),性能很好。
与Set相关的常用命令如下。
➢ SADD key member [member…]:向key对应的Set中添加一个
或多个元素。
➢ SCARD key:返回key对应的Set中元素的个数。
➢ SDIFF key [key…]:计算多个Set之间的差值。
➢ SDIFFSTORE destination key [key…]:SDIFF的存储版本,将多个Set之间的差值保存到destination中。
➢ SINTER key [key…]:返回给定Set的交集。
➢ SINTERSTORE destination key [key…]:SINTER的存储版本,将给定Set的交集保存到destination中。
➢ SISMEMBER key member:判断member是否为key对应的Set的元素。
➢ SMEMBERS key:返回key对应的Set的全部元素。
➢ SMOVE source destination member:将source中的member元素移到destination中。
➢ SPOP key:弹出key对应的Set中随机的一个元素。
➢ SRANDMEMBER key [count]:返回key对应的Set中随机的count个元素(不删除元素)。
➢ SREM key member [member…]:删除key对应的Set中的一个或多个元素。
➢ SUNION key [key…]:计算给定Set的并集。
➢ SUNIONSTORE destination key [key…]:SUNION的存储版本,将给定Set的并集保存到destination中。
在这里插入图片描述

6.ZSet命令

ZSet相当于Set 的增强版,它会为每个元素都分配一个double类型的score(分数),并按该score对集合中元素进行排序。
ZSet集合中的元素不允许重复,但元素的score是可以重复的。
与ZSet相关的常用命令如下。
➢ ZADD key score member [score member…]:向ZSet中添加一个或多个元素,或者更新已有元素的score。
➢ ZCARD key:返回key对应的ZSet中元素的个数。
➢ ZCOUNT key min max:返回ZSet中score位于min和max之间的元素个数。
➢ ZDIFF numkeys key [key…] [WITHSCORES]:计算给定ZSet之间的差值。该命令在Redis 6.2及更新版本中才可用。
➢ ZDIFFSTORE destination numkeys key [key…]:ZDIFF的存储版本,将给定ZSet之间的差值保存到destination中。该命令在Redi
s 6.2及更新版本中才可用。
➢ ZINCRBY key increment member:将memeber元素的score增加increment。
➢ ZINTER numkeys key [key…]:计算给定ZSet的交集。该命令在Redis 6.2及更新版本中才可用。
➢ ZINTERSTORE destination numkeys key [key…]:ZINTER的存储版本,将给定ZSet的交集保存到destination中。交集中元素的sc
ore是相同元素的score之和。
➢ ZLEXCOUNT key min max:返回ZSet中按字典排序时从min到max之间所有元素的个数。
提示:
当向ZSet中添加多个score相等的元素时,ZSet就会使用字典顺序
(英文字典中字母的排序方式)对这些元素进行排序,此时就可按字
典顺序来获取指定范围内元素的个数。
➢ ZPOPMAX key [count]:弹出ZSet中score最大的元素。
➢ BZPOPMAX key [key…] timeout:ZPOPMAX的阻塞版本。该命令会阻塞进程,直到指定ZSet有元素弹出或超时。
➢ ZPOPMIN key [count]:弹出ZSet中score最小的元素。
➢ BZPOPMIN key [key…] timeout:ZPOPMIN的阻塞版本。该命令会阻塞进程,直到指定ZSet有元素弹出或超时。
➢ ZRANGE key start stop [WITHSCORES]:返回ZSet中从start索引到stop索引范围内的元素(及score)。索引支持负数,负数表示
从最后面开始,比如-1代表最后一个元素。
➢ ZRANGEBYLEX key min max [LIMIT offset count]:返回ZSet
中按字典排序时从min到max之间的所有元素。
➢ ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]:返回ZSet中score位于min和max之间的所有元素。
➢ ZRANK key member:返回ZSet中指定元素的索引。score最小的元素的索引是0。
➢ ZREM key member [member…]:删除ZSet中一个或多个元素。
➢ ZREMRANGEBYLEX key min max:删除ZSet中按字典排序时从min到max之间的所有元素。
➢ ZREMRANGEBYRANK key start stop:删除ZSet中从start索引到stop索引之间的所有元素。
➢ ZREMRANGEBYSCORE key min max:删除ZSet中score位于min和max之间的所有元素。
➢ ZREVRANGE key start stop [WITHSCORES]:ZRANGE的反向版本。
➢ ZREVRANGEBYLEX key max min [LIMIT offset count]:ZRANGEBYLEX的反向版本。
➢ ZREVRANGEBYSCORE key max min [WITHSCORES]:ZRANGEBYSCORE的反向版本。
➢ ZREVRANK key member:ZRANK的反向版本。score最大的元素的反向索引是0。
➢ ZSCORE key member:获取指定元素的score。
➢ ZUNION numkeys key [key…]:计算给定ZSet的并集。该命令在Redis 6.2及更新版本中才可用。
➢ ZUNIONSTORE destination numkeys key [key…]:ZUNION的存储版本,将给定ZSet的并集保存到destination中。
➢ ZMSCORE key member [member…]:获取多个元素的score。该命令在Redis 6.2及更新版本中才可用。
在这里插入图片描述在这里插入图片描述

7.Hash相关命令

Hash类型是一个key和value都是String类型的key-value对。Hash类型适合存储对象。每个Hash最多可存储232-1个key-value对。
与Hash相关的常用命令如下。
➢ HDEL key field [field…]:删除Hash对象中一个或多个key-value对。此处的field参数其实代表Hash对象中的key,后面提到的f
ield参数皆如此。
➢ HEXISTS key field:判断Hash对象中指定的key是否存在。
➢ HGET key field:获取Hash对象中指定key对应的value。
➢ HGETALL key:获取Hash对象中所有的key-value对。
➢ HINCRBY key field increment:为Hash对象中指定的key增加increment。
➢ HINCRBYFLOAT key field increment:HINCRBY的浮点数版本,支持小数。
➢ HKEYS key:获取Hash对象中所有的key。
➢ HLEN key:获取Hash对象中key-value对的数量。
➢ HMGET key field [field…]:HGET的加强版,可同时获取多个key对应的value。
➢ HSET key field value:为Hash对象设置一个key-value对。如果field对应的key已经存在,新设置的value将会覆盖原有的value。
➢ HMSET key field value [field value…]:HSET的加强版,可同时设置多个key-value对。
➢ HSETNX key field value:HSET的安全版本,只有当field对应的key不存在时,才能设置成功。
➢ HSTRLEN key field:获取Hash对象中指定key对应的value的字符串长度。
➢ HVALS key:获取Hash对象中所有的value。
在这里插入图片描述

8.事务相关命令

Redis事务保证事务内的多条命令会按顺序作为整体执行,其他客户端发出的请求绝不可能被插入到事务处理的中间,这样可以保证事
务内所有的命令作为一个隔离操作被执行。Redis事务同样具有原子性,事务内所有的命令要么全部被执行,要么全部被放弃。比如Redis在事务执行过程中遇到数据库宕机,假如事务已经执行了一半的命令,Redis将会自动回滚这些已经执行过的命令。注意某条命令执行出现错误并不会影响事务的提交。
与事务相关的常用命令如下。
➢ DISCARD:取消事务,放弃执行事务块内的所有命令。
➢ EXEC:执行事务。
➢ MULTI:开启事务。
➢ WATCH key [key…]:监视一个或多个key,如果在事务执行
之前这些key对应的值被其他命令改动,事务会自动中断。
➢ UNWATCH:取消WATCH命令对所有key的监视。
在这里插入图片描述

9.Java代码运行示例

记得导入依赖!!

        <dependency>
            <groupId>io.lettuce</groupId>
            <artifactId>lettuce-core</artifactId>
        </dependency>

9.1Redis同步请求代码

package com.example.domain;

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;

public class Syn {
    public static void main(String[] args) {
        load_redis();
    }

    private static void load_redis() {
        RedisURI uri = RedisURI.builder().withHost("localhost")
                .withPort(6379)
                .withDatabase(0)
                .withPassword(new char[]{
                        '1', '2', '3', '4', '5', '6'
                }).withTimeout(Duration.ofMinutes(5)).build();
        RedisClient redisClient = RedisClient.create(uri);
        StatefulRedisConnection<String, String> connect = redisClient.connect();
        RedisCommands<String, String> cmd = connect.sync();
        cmd.set("name","fkjava");
        cmd.hmset("user", Map.of("name","fkjava","age","25","height","182"));
        cmd.sadd("items","鼠标","要是","钱包");
        cmd.zadd("test",3.0,"java");
        cmd.zadd("test", ScoredValue.just(2.0,"kotlin"),ScoredValue.just(2.5,"python"));
        connect.close();
        redisClient.shutdown();
    }
}

在这里插入图片描述
在这里插入图片描述

9.2Redis异步请求代码

package com.example.domain;

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.sync.RedisCommands;

import java.time.Duration;
import java.util.Map;
//异步请求
//异步请求
//异步请求
//异步请求
//异步请求
//异步请求
public class ASyn {
    private RedisClient client;
    private StatefulRedisConnection<String,String> conn;
    public void init(){
        RedisURI uri = RedisURI.builder().withHost("localhost")
                .withPort(6379)
                .withDatabase(2)
                .withPassword(new char[]{
                        '1', '2', '3', '4', '5', '6'
                }).withTimeout(Duration.ofMinutes(5)).build();
        this.client = RedisClient.create(uri);
        this.conn = client.connect();
    }
    public void AccessRedis(){
//        创建异步方式
        RedisAsyncCommands<String, String> cmd = conn.async();
        cmd.set("name","fkjava").thenAccept(System.out::println);
        cmd.hmset("user", Map.of("name","fkjava","age","25","height","182")).thenAccept(System.out::println);
        cmd.sadd("items","鼠标","要是","钱包").thenAccept(System.out::println);
        cmd.zadd("test",3.0,"java").thenAccept(System.out::println);
        cmd.zadd("test", ScoredValue.just(2.0,"kotlin"),ScoredValue.just(2.5,"python")).thenAccept(System.out::println);
    }
    public void closeResource(){
        conn.close();
        client.shutdown();
    }

    public static void main(String[] args) {
        ASyn app = new ASyn();
        app.init();
        app.AccessRedis();
        app.closeResource();
    }
}

9.3Redis反应式请求代码

package com.example.domain;

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 java.time.Duration;
import java.util.Map;
//反应式请求
//反应式请求
//反应式请求
//反应式请求
//反应式请求
//反应式请求
//反应式请求
//反应式请求
//反应式请求
public class Reactive {
    private RedisClient client;
    private StatefulRedisConnection<String,String> conn;
    public void init(){
        RedisURI uri = RedisURI.builder().withHost("localhost")
                .withPort(6379)
                .withDatabase(3)
                .withPassword(new char[]{
                        '1', '2', '3', '4', '5', '6'
                }).withTimeout(Duration.ofMinutes(5)).build();
        this.client = RedisClient.create(uri);
        this.conn = client.connect();
    }

    /**
     * 对于反应式API,由于测试时想要立即获取结果,因此需要使用block来阻塞县城,获取反应式方法的结果。否则你的程序已经退出了,但反应式方法搜返回的Mono或Flux中数据还未到来.
     * 但如果你结合WebFlux使用反应式API,你可以直接让你控制器返回Mono或者Flux,这样就不需要block了。
     * 如果前端用的WEbFlux,后端用反应式api是很爽的,但如果前端用的是普通Spring MVC,那就不太理想了。
     */
    public void AccessRedis(){
//        创建反应式
        RedisReactiveCommands<String, String> cmd = conn.reactive();
        System.out.println(cmd.set("name","fkjava").block());
        System.out.println(cmd.hmset("user", Map.of("name","fkjava","age","25","height","182")).block());
        System.out.println(cmd.sadd("items","鼠标","要是","钱包").block());
        System.out.println(cmd.zadd("test",3.0,"java").block());
        System.out.println(cmd.zadd("test", ScoredValue.just(2.0,"kotlin"),ScoredValue.just(2.5,"python")).block());
    }
    public void closeResource(){
        conn.close();
        client.shutdown();
    }

    public static void main(String[] args) {
        Reactive app = new Reactive();
        app.init();
        app.AccessRedis();
        app.closeResource();
    }
}

10.订阅发布的Redis的Java代码演示

先启动Subscriber1和2的,后启动Publisher.java的,注意:public void subscribed(String channel, long count)的count是表示有几个订阅的意思!
Redis对象池的依赖


		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-pool2</artifactId>
			<version>2.10.0</version>
		</dependency>

1.Subscriber.java

package org.crazyit.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 io.lettuce.core.pubsub.RedisPubSubAdapter;
import io.lettuce.core.pubsub.StatefulRedisPubSubConnection;
import io.lettuce.core.pubsub.api.sync.RedisPubSubCommands;
import io.lettuce.core.support.ConnectionPoolSupport;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

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

/**
 * Description:<br>
 * 网站: <a href="http://www.crazyit.org">疯狂Java联盟</a><br>
 * Copyright (C), 2001-2022, Yeeku.H.Lee<br>
 * This program is protected by copyright laws.<br>
 * Program Name:<br>
 * Date:<br>
 *
 * @author Yeeku.H.Lee kongyeeku@163.com 公众号: fkbooks<br>
 * @version 1.0
 */
public class Subscriper
{
	private RedisClient redisClient;
	private GenericObjectPool<StatefulRedisPubSubConnection<String, String>> pool;

	public void init()
	{
		// 1 定义RedisURI
		var uri = RedisURI.builder()
				.withHost("127.0.0.1")
				.withPort(6379)
				.withDatabase(1)
				.withPassword(new char[]{'1', '2', '3', '4', '5','6'})
				.withTimeout(Duration.ofMinutes(5))
				.build();
		// 2. 创建RedisClient
		this.redisClient = RedisClient.create(uri);
		var conf = new GenericObjectPoolConfig<StatefulRedisPubSubConnection<String, String>>();
		conf.setMaxTotal(20); // 设置允许的最大连接数
		// 3. 创建连接池对象(其中连接由redisClient的connectPubSub方法创建)
		pool = ConnectionPoolSupport.createGenericObjectPool(
				this.redisClient::connectPubSub, conf);
	}

	public void closeResource()
	{
		// 关闭连接池
		this.pool.close();
		this.redisClient.shutdown();
	}

	public void subscribe() throws Exception
	{
		// 从连接池中取出连接
		StatefulRedisPubSubConnection<String, String> conn = this.pool.borrowObject();
		// 4. 创建RedisPubSubCommands
		RedisPubSubCommands cmd = conn.sync();

		// 消息到来时,肯定是通过监听器来实现的
		conn.addListener(new RedisPubSubAdapter<>()
		{
			@Override
			public void message(String channel, String message)
			{
				System.out.printf("从%s收到消息:%s\n", channel, message);
			}

			@Override
			public void subscribed(String channel, long count)
			{
				System.out.println("完成订阅" + count);
			}

			@Override
			public void unsubscribed(String channel, long count)
			{
				System.out.println("取消订阅" + count);
			}
		});

		// 订阅channel
		cmd.subscribe("c1", "c2");
	}
	public static void main(String[] args) throws Exception
	{
		Subscriper s = new Subscriper();
		s.init();
		s.subscribe();
		// 该程序就只订阅1min
		Thread.sleep(60000);
		// 5. 关闭资源
		s.closeResource();
	}
}

2.subscriber2.java

package org.crazyit.app;

import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.pubsub.RedisPubSubAdapter;
import io.lettuce.core.pubsub.StatefulRedisPubSubConnection;
import io.lettuce.core.pubsub.api.sync.RedisPubSubCommands;
import io.lettuce.core.support.ConnectionPoolSupport;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

import java.time.Duration;

/**
 * Description:<br>
 * 网站: <a href="http://www.crazyit.org">疯狂Java联盟</a><br>
 * Copyright (C), 2001-2022, Yeeku.H.Lee<br>
 * This program is protected by copyright laws.<br>
 * Program Name:<br>
 * Date:<br>
 *
 * @author Yeeku.H.Lee kongyeeku@163.com 公众号: fkbooks<br>
 * @version 1.0
 */
public class Subscriper2
{
	private RedisClient redisClient;
	private GenericObjectPool<StatefulRedisPubSubConnection<String, String>> pool;

	public void init()
	{
		// 1 定义RedisURI
		var uri = RedisURI.builder()
				.withHost("127.0.0.1")
				.withPort(6379)
				.withDatabase(1)
				.withPassword(new char[]{'1', '2', '3', '4', '5','6'})
				.withTimeout(Duration.ofMinutes(5))
				.build();
		// 2. 创建RedisClient
		this.redisClient = RedisClient.create(uri);
		var conf = new GenericObjectPoolConfig<StatefulRedisPubSubConnection<String, String>>();
		conf.setMaxTotal(20); // 设置允许的最大连接数
		// 3. 创建连接池对象(其中连接由redisClient的connectPubSub方法创建)
		pool = ConnectionPoolSupport.createGenericObjectPool(
				this.redisClient::connectPubSub, conf);
	}

	public void closeResource()
	{
		// 关闭连接池
		this.pool.close();
		this.redisClient.shutdown();
	}

	public void subscribe() throws Exception
	{
		// 从连接池中取出连接
		StatefulRedisPubSubConnection<String, String> conn = this.pool.borrowObject();
		// 4. 创建RedisPubSubCommands
		RedisPubSubCommands cmd = conn.sync();

		// 消息到来时,肯定是通过监听器来实现的
		conn.addListener(new RedisPubSubAdapter<>()
		{
			@Override
			public void message(String channel, String message)
			{
				System.out.printf("从%s收到消息:%s\n", channel, message);
			}

			@Override
			public void subscribed(String channel, long count)
			{
				System.out.println("完成订阅" + count);
			}

			@Override
			public void unsubscribed(String channel, long count)
			{
				System.out.println("取消订阅" + count);
			}
		});

		// 订阅channel
		cmd.subscribe("c2");
	}

	public static void main(String[] args) throws Exception
	{
		Subscriper2 s = new Subscriper2();
		s.init();
		s.subscribe();
		// 该程序就只订阅1min
		Thread.sleep(60000);
		// 5. 关闭资源
		s.closeResource();
	}
}

3.Publisher.java

package org.crazyit.app;

import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.pubsub.RedisPubSubAdapter;
import io.lettuce.core.pubsub.StatefulRedisPubSubConnection;
import io.lettuce.core.pubsub.api.sync.RedisPubSubCommands;
import io.lettuce.core.support.ConnectionPoolSupport;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

import java.time.Duration;

/**
 * Description:<br>
 * 网站: <a href="http://www.crazyit.org">疯狂Java联盟</a><br>
 * Copyright (C), 2001-2022, Yeeku.H.Lee<br>
 * This program is protected by copyright laws.<br>
 * Program Name:<br>
 * Date:<br>
 *
 * @author Yeeku.H.Lee kongyeeku@163.com 公众号: fkbooks<br>
 * @version 1.0
 */
public class Publisher
{
	private RedisClient redisClient;
	private GenericObjectPool<StatefulRedisPubSubConnection<String, String>> pool;

	public void init()
	{
		// 1 定义RedisURI
		var uri = RedisURI.builder()
				.withHost("127.0.0.1")
				.withPort(6379)
				.withDatabase(1)
				.withPassword(new char[]{'1', '2', '3', '4', '5','6'})
				.withTimeout(Duration.ofMinutes(5))
				.build();
		// 2. 创建RedisClient
		this.redisClient = RedisClient.create(uri);
		var conf = new GenericObjectPoolConfig<StatefulRedisPubSubConnection<String, String>>();
		conf.setMaxTotal(20); // 设置允许的最大连接数
		// 3. 创建连接池对象(其中连接由redisClient的connectPubSub方法创建)
		pool = ConnectionPoolSupport.createGenericObjectPool(
				this.redisClient::connectPubSub, conf);
	}

	public void closeResource()
	{
		// 关闭连接池
		this.pool.close();
		this.redisClient.shutdown();
	}

	public void publish() throws Exception
	{
		// 从连接池中取出连接
		StatefulRedisPubSubConnection<String, String> conn = this.pool.borrowObject();
		// 4. 创建RedisPubSubCommands
		RedisPubSubCommands cmd = conn.sync();

		// 发布两条消息
		cmd.publish("c2", "欢迎学习Redis的消息机制");
		cmd.publish("c1", "Redis其实很简单");

		// 5. 关闭资源
		this.closeResource();
	}

	public static void main(String[] args) throws Exception
	{
		Publisher s = new Publisher();
		s.init();
		s.publish();
		s.closeResource();
	}
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

11.杂碎的Redis笔记

★ Lettuce的核心API

  • RedisURI:用于封装Redis服务器的URI信息。

  • RedisClient:代表Redis客户端,如果连接Cluster模式的Redis,则使用RedisClusterClient。
    有点类似于redis-cli工具。

  • StatefulConnection<K,V>:代表Redis连接的父接口,它派生了不少子接口来代表不同的连接。

  • RedisCommands:用于执行Redis命令的接口,它的方法几乎覆盖了Redis的所有命令(前面介绍的那些命令全部都支持)
    它的方法名和Redis命令名也是一一对应的,肯定一看就会,
    比如Redis对操作Hash对象提供了hmset命令,那RedisCommands就支持hmset()方法,
    它派生了一个RedisPubSubCommands<K,V>子接口,用于运行消息发布/订阅的命令。

★ Lettuce编程步骤:

 使用Lettuce操作Redis的大致步骤如下:

(1)定义RedisURI(有点类似于数据库的URL),再以RedisURI为参数,创建RedisClient或RedisClusterClient对象。
(2)调用RedisClient或RedisClusterClient的connectXxx()方法连接Redis服务器,根据所连接的Redis服务器的状态不同,该方法返回StatefulRedisXxxConnection连接对象。
(3)调用连接对象的sync()、async()或reactive()方法创建同步、异步或反应式模式的RedisCommands对象。
(4)调用RedisCommands执行Redis命令。这一步是变化最多的,因为RedisCommands可以执行Redis的全部命令。
(5)关闭资源。关闭资源时按照惯例“先开后闭”,因此先关闭与Redis的连接对象,再关闭RedisClient对象。 

 URI  →  创建Client → 建立连接  → 创建RedisCommands → 执行命令 → 关闭资源

★ 构建RedisURI:

Lettuce提供了如下三种方式来构建RedisURI:

A. 调用静态的create()方法。这种方式要求把所有的连接信息都写在create()方法的String参数中。
   该String参数既支持单机模式的Redis,也支持集群模式的Redis,也支持哨兵模式的Redis。

B. 调用Builder来构建。这种构建方式下,所有信息都通过Builder对应的方法逐项传入,

   因此可读性最好,这也是我所推荐的方式。 

C. 调用构造器来构建。这种方式是最不灵活的方式,因为它只能传入3个构造器参数,
   通过该方式构建RedisURI之后还需要调用它的setter方法对它进行设置,这种方式是最差的一种。

★ 从RedisClient到StatefulConnection对象(连接)
——获取与Redis服务器的连接

以RedisURI为参数,调用RedisClient(或RedisClusterClient)的create()静态方法即可创建RedisClient(或RedisClusterClient)对象。
根据Redis运行模式调用RedisClient或RedisClusterClient对象对应的connectXxx()方法获取StatefulConnection对象。

▲ StatefulConnection提供如下常用子接口:

- StatefulRedisConnection:最基本的Redis连接。
- StatefulRedisPubSubConnection:带消息发布/订阅功能的Redis连接。
- StatufulRedisMasterSlaveConnection:主从模式的Redis连接。
- StatefulRedisSentinelConnection:哨兵模式的Redis连接。 

★ 从StatefulConnection到RedisXxxCommands对象

调用StatefulRedisXxxConnection连接对象的以下三个方法来创建RedisXxxCommands对象。

  • sync():创建同步模式的RedisCommands对象。
  • async():创建异步模式的RedisAsyncCommands对象。
  • reactive():创建反应式模式的RedisReactiveCommands对象。

RedisCommands的作用类似于redis-cli.exe工具,用于执行各种Redis命令。
其中RedisAsyncCommands是异步版本,而RedisReactiveCommands则是反应式版本

★ 使用连接池管理Redis连接

从Redis 6.0开始,Redis可支持使用多线程来接收、处理客户端命令,因此应用程序可使用连接池来管理Redis连接。

Lettuce连接池支持需要Apache Commons Pool2的支持

接下来即可在程序中通过类似如下代码片段来创建连接池了。

var conf = new GenericObjectPoolConfig<StatefulRedisConnection<String, String>>();
conf.setMaxTotal(20); // 设置允许的最大连接数
// 创建连接池对象(其中连接由redisClient的connectPubSub方法创建)
pool = ConnectionPoolSupport.createGenericObjectPool(
redisClient::connect, conf);

★ Spring Boot为Redis提供的自动配置

spring-boot-starter-data-redis使用Spring Data Redis对底层Lettuce(或Jedis)进行了封装。

▲ 自动配置

Spring Boot会为Redis自动配置RedisConnectionFactory、
SpringBoot支持两种配置连接:Lettuce,Jedis。
StringRedisTemplate,
ReactiveStringRedisTemplate(反应式API),因此可将它们注入任意其他组件(比如DAO组件)。



如果配置了自定义的RedisConnectionFactory ,Spring Boot就不会自动配置RedisConnectionFactory。

但RedisTemplate可额外配置很多个,只要额外配置的RedisTemplate的id不是redisTemplate,
Spring Boot依然会自动配置id为redisTemplate的RedisTemplate。

StringRedisTemplate则不同,只要你在容器中配置了类型为StringRedisTemplate Bean,自动配置将不再配置它。  

★ Redis配置相关的属性

可通过spring.redis.*开头的属性进行配置连接的服务器(该配置属于由RedisProperties类负责处理),例如如下配置:
spring.redis.host=192.168.1.188
spring.redis.port=6380
如果你指定了url属性,host, port, and password这些属性就会被覆盖

如果类加载路径下包含了Apache Commons Pool2依赖库,Spring Boot会使用连接池管理连接。可通过spring.redis.lettuce.pool.*开头的属性配置连接池。例如如下两行配置了有关连接池的信息:

# 指定连接池中最大的活动连接数为20
spring.redis.lettuce.pool.maxActive = 20
# 指定连接池中最大的空闲连接数为20
spring.redis.lettuce.pool.maxIdle=20 

★ RedisTemplate

RedisTemplate是Spring Data Redis提供的,它相当于一个操作Redis数据库的门面类。

它提供如下方法来操作数据库:
一般用的都是它的子类:StringRedisTemplate——相当于它的key、value都是String类型:

- <HK,HV> HashOperations<K,HK,HV> opsForHash():返回操作Hash对象的HashOperations对象。 
- ListOperations<K,V> opsForList():返回操作List对象的ListOperations对象。
- SetOperations<K,V> opsForSet():返回操作Set对象的SetOperations对象。
- ValueOperations<K,V> opsForValue():返回操作String对象的ValueOperations对象。
- ZSetOperations<K,V> opsForZSet():返回操作Zset对象的ZSetOperations<K,V> 对象。

【注意:】 程序实际上应该使用StringRedisTemplate来操作Redis数据库。

★ RedisTemplate VS RedisCommands

- RedisCommands的做法是它自己为Redis所有命令定义了对应的方法;

- RedisTemplate对Redis命令进行了分类,不同的命令由不同的接口提供支持:
  比如操作List的命令,由ListOperations负责提供;操作Set的命令,则由SetOperations负责提供;

  而RedisTemplate只是提供opsForXxx()方法来返回相应的操作接口。 

- RedisTemplate还提供了一些直接操作key的方法,例如delete(K key)(删key)、
  getExpire(K key)(获取key的过期时间)、move(K key, int dbIndex)(移动key)、

  rename(K oldKey, K newKey)(重命名key)等方法 


▲ 很明显,还是用Spring Bot Data Redis编程更简单。

 如果你直接用Lettuce编程,你需要自行创建RedidUri, RedisClient,StatefuleConnection,最后才能得到RedisCommand。
 但如果你用Spring Boot data Reids,Spring Boot可以自动配置RedisTEmplate,并将它注入DAO组件,因此方便得多。

★ Spring Data Redis的功能

 DAO接口只需继承CrudRepository,Spring Data Redis能为DAO组件提供实现类。

 - Spring Data Redis支持方法名关键字查询,只不过Redis查询的属性必须是被索引过的
   (索引就是为它建立对应的key,这样才能被查询)

 - Spring Data Redis同样支持DAO组件添加自定义的查询方法
   ——通过添加额外的父接口,并为额外的父接口提供实现类,
   Spring Data Redis就能该实现类中的方法“移植”到DAO组件中。

 - Spring Data Redis同样支持Example查询。

 A. 不支持@Query的自定义查询;
 B. 也不支持方法名查询中定义复杂的运算符;
 C. 也不支持Specification查询。

★ 方法名关键字查询

 Spring Data Redis的方法名关键字查询不如JPA那么强大,这是由Redis底层决定:
 Redis并不支持任何查询,它是一个简单的key-value数据库,
 因此它获取数据的唯一方式就是根据key获取value。因此它不能支持GreaterThan、LessThan、Like……等复杂关键字,它只能支持如下简单的关键字:

 - And:例如在接口中可以定义“findByNameAndAge”。
 - Or:例如“findByNameOrAge”。
 - Is、Equals:例如“findByNameIs”、“findByName”、“findByNameEquals”。
   这种表示相同或相等的关键字不加也行。
 - Top、First:例如“findFirst5Name”、“findTop5ByName”,实现查询前5条记录。

★ 注解

 Spring Data Redis提供了如下两个注解:

 - @RedisHash:该注解指定将数据类映射到Redis的Hash对象。类似于JPA的@Entity。
 - @TimeToLive:该注解修饰一个数值类型的属性,用于指定该对象的过期时长。

 Spring Data Redis还提供了如下两个索引化注解:

 - @Indexed:指定对普通类型的属性建立索引,索引化后的属性可用于查询。
 - @GeoIndexed:指定对Geo数据(地理数据)类型的属性建立索引。

★ Spring Data Redis的存储机制

 - key为books(由@RedisHash注解指定)的value是一个Set,Set中元素就是每个Book对象的标识属性值。

 - key为“books:<id值>”对应的Hash对象,就保存一个一个的持久化对象的全部信息。
   你的程序保存了几个持久化对象,Redis中就有几个key为“books:id值”格式的key-value对。

 - 每个索引后的属性,都会建立对应key。
   比如你对author属性建立了索引(@Indexed修饰),Spring Data Redis就会在数据库中建立以
   “books:author:*”开头的key,其中*就代表索引属性的每个可能的值。
   比如你对name属性建立了索引(@Indexed修饰),Spring Data Redis就会在数据库中建立以
   “books:name:*”开头的key,其中*就代表索引属性的每个可能的值。

   这种索引key对应的value是Set类型,该Set的元素就是该key对应的所有实体的id值。


 - 每个实体,都会有一个单独key。
   books: <id值>: idx: 该key对应的value是Set,该Set集合就保存在实体所支持的全部的索引属性key。


 ▲ 假设Spring Data Redis要查询ID为2的Book对象

 (1)确定Book类上的@RedisHash,该注解指定Book对应的key前缀为books

 (2)Redis获取key为 “books:2”对应value,该value是被查询对象的全部信息。


 ▲ 根据索引属性来查询,假设Spring Data Redis要查询name为Python的Book对象

 (1)确定Book类上的@RedisHash,该注解指定Book对应的key前缀为books

 (2) Redis获取key为" books:name:Python"所对应的value。

 (3)该value返回的就是Set,该Set中的每个值都是ID。

 (4)遍历第3步中Set里的每个ID,然后Redis获取key为 “books:<ID>”对应value,该value是被查询对象的全部信息。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/858036.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android模板设计模式之 - 构建整个应用的BaseActivity

1. 模式介绍 模式的定义 定义一个操作中的算法的框架&#xff0c;而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 模式的使用场景 1.多个子类有公有的方法&#xff0c;并且逻辑基本相同时。 2.重要、复杂的算法&#xff0c;可…

基于Tars高并发IM系统的设计与实现-实战篇6

基于Tars高并发IM系统的设计与实现-实战篇6 客户端设计实现 客户端采用跨平台SDK原生UI的方案。 此处重点介绍SDK实现&#xff0c;UI用户可以根据自己需求进行开发。 方案架构图&#xff1a; 方案实现: TCP链接 CTcpSocket CSSLSocket 长链接维护、数据收发 CTNSendRecvThr…

PHP最简单自定义自己的框架控制器自动加载运行(四)

1、实现效果调用控制中方法 2、创建控制器indexCrl.php <?php class indexCrl{public function index(){echo 当前index控制器index方法;} } 3、KJ.php字段加载控制器文件 public static function run(){//定义常量self::_set_const();//创建模块目录self::_mk_module();…

Windows下运行Tomcat服务时报GC Overhead Limit Exceeded

根本原因是在新建Tomcat作为Windows服务时&#xff0c;系统默认设置的堆内存太小了&#xff0c;我们打开/bin/service.bat文件&#xff0c;将如下图所示的默认值改大一些就好了 if "%JvmMs%" "" set JvmMs512 if "%JvmMx%" "" set J…

嵌入式AI芯片架构用处

Blaize将其GSP描述为能够执行“直接图处理&#xff0c;片上任务图管理和执行以及任务并行性”。简而言之&#xff0c;Blaize设计了GSP来满足AI&#xff0c;GPU&#xff0c;CPU或DSP以前无法满足的处理需求。 对于许多涉及嵌入式ai处理器的行业分析师而言&#xff0c;这是他们之…

算法通关村——轻松搞定最大深度问题

前言 二叉树的深度&#xff1a;从根节点到当前节点的最长简单路径边的条数 题目 给定一个二叉树&#xff0c;找出其最大深度&#xff0c;二叉树的深度为根节点到最远叶子节点的最长路径上的节点数 说明 如下图所示&#xff0c;对于node(3) &#xff0c; 最大深度自然是左右子节…

pmp考试是智商税吗,是一场持久的割韭菜战吗?

在一些大型企业中&#xff0c;PMP认证已成为担任“项目经理”必备的资格之一。此外&#xff0c;在国际上&#xff0c;PMP认证也成为参与项目招标的必要条件之一&#xff0c;只有拥有PMP认证的项目经理所在的公司才有资格参与竞标&#xff0c;而承建项目经理也必须持有PMP认证。…

RabbitMQ 安装教程

RabbitMQ 安装教程 特殊说明 因为RabbitMQ基于Erlang开发&#xff0c;所以安装时需要先安装Erlang RabbitMQ和Erlang版本对应关系 查看地址&#xff1a;www.rabbitmq.com/which-erlan… 环境选择 Erlang: 23.3及以上 RabbitMQ: 3.10.1Windows 安装 1. 安装Erlang 下载地…

海外进出口跨境电商独立站开发(多语言+多货币)

要搭建一个海外进出口跨境电商独立站开发&#xff0c;需要考虑以下几个方面&#xff08;以下步骤不分先后&#xff09;&#xff1a; 设计系统架构在开始编写代码之前&#xff0c;首先需要设计系统的整体架构。对于一个大型的电商系统&#xff0c;需要考虑系统可扩展性、高可用…

NameError: No such file or directory 解决方法

前言 嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 问题 最近有小伙伴经常问到这个报错&#xff0c;今天来分享一下具体怎么解决。 [Errno 2] No such file or directory: ./mnist_image_label/mnist_train_jpg_60000.txt这个没有查找到子文件或者子文件夹的问题 解决…

CPU与硬件的交互方式(中断、轮询)

CPU与硬件的交互方式 轮询方式&#xff1a;CPU不断的访问硬件有没有进行操作&#xff0c;如果接收到了信息&#xff0c;CPU就处理。如果没有过一会在访问一遍 直到有信息为止 中断方式&#xff1a;硬件操作的时候会写一个中断&#xff0c;向CPU发送这个中断&#xff0c;CPU正常…

【LeetCode】练习习题集【4月 - 7 月】

LEETCODE习题集【4月-7月总结】 简单 数组部分 1.重复数 题目&#xff1a; 在一个长度u为 n 的数组 nums 里的所有数字都在 0&#xff5e;n-1 的范围内。数组中某些数字是重复的&#xff0c;但不知道有几个数字重复了&#xff0c;也不知道每个数字重复了几次。请找出数组中…

网络安全—黑客技术【自学】

一、黑客是什么 原是指热心于计算机技术&#xff0c;水平高超的电脑专家&#xff0c;尤其是程序设计人员。但后来&#xff0c;黑客一词已被用于泛指那些专门利用电脑网络搞破坏或者恶作剧的家伙。 二、学习黑客技术的原因 其实&#xff0c;网络信息空间安全已经成为海陆空之…

Linux驱动——input子系统

一、input子系统基本框架 Linux内核为了两个目的&#xff1a; 简化纯输入类外设&#xff08;如&#xff1a;键盘、鼠标、游戏杆、轨迹球、触摸屏。。。等等&#xff09;的驱动开发 统一输入类外设产生的数据格式&#xff08;struct input_event&#xff09;&#xff0c;更加方…

将你的计算机变身为果园守护者:与本地树莓派建立连结的乐趣探索!!

如何连接本地树莓派 文章目录 如何连接本地树莓派前言1. 操作流程2. 打开树莓派SSH功能3. 确认树莓派信息后 安装相应SSH客户端 &#x1f341; 小结 &#x1f341; 前言 树莓派作为一款以教育为目的推出的硬件系统&#xff0c;也是超低功耗的微型“准系统”&#xff0c;能够提…

Redis的RDB持久化

Redis是一个键值对数据库服务器&#xff0c;服务器中通常包含着任意个非空数据库&#xff0c;而每个非空数据库中又可以包含任意个键值对&#xff0c;为了方便起见&#xff0c;我们将服务器中的非空数据库以及它们的键值对统称为数据库状态。 举个例子&#xff0c;下图展示了一…

模仿学习(行为克隆,逆强化学习,生成式对抗模仿学习)

目录 1.模仿学习 1.1先说强化学习 1.2再说逆强化学习 1.3最后说生成对抗模仿学习 1.3.1先说GAN 1.3.2再说生成对抗模仿学习 1.4逆强化学习常用方法 参考文献 1.模仿学习 定义&#xff1a;当我们想训练机器人时&#xff0c;通过复制人类的动作&#xff0c;对机器人进行训…

ssm新生报到系统源码和论文PPT

ssm新生报到系统源码和论文PPT004 开发环境 开发工具&#xff1a;idea 数据库mysql5.7(mysql5.7最佳) 数据库链接工具&#xff1a;navcat,小海豚等 开发技术&#xff1a;java ssm tomcat8.5 选题依据及意义 每学年九月份随着新生的入校&#xff0c;学校工作中的重点都会集…

Endnote中导入和显示中文文献国标格式具体实现步骤

Endnote中导入和显示中文文献国标格式具体实现步骤 目录 Endnote中导入和显示中文文献国标格式具体实现步骤一、下载中文文献引用标准格式二、将下载的两种格式复制到Endnote安装文件下的Styles子文件夹中三、对导入的样式进行标记&#xff0c;以便在word中方便显示和使用四、在…

领航优配:美联储货币政策风向或已生变 私行纵论下半年黄金配置价值

美联储钱银方针风向或已生变&#xff0c;黄金的拥趸开端跃跃欲试。 费城联储主席帕特里克哈克周二标明&#xff0c;美国有一条通往经济软着陆的路径&#xff0c;失业率或许有所上升&#xff0c;但起伏不会太大&#xff1b;不希望美联储过度收紧钱银方针&#xff0c;估计明年某时…