当前位置: 首页 > news >正文

Redis学习笔记Day01-Redis入门

声明:本博客部分内容是从终极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 定义RedisURIvar 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. 创建RedisClientthis.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. 创建RedisPubSubCommandsRedisPubSubCommands cmd = conn.sync();// 消息到来时,肯定是通过监听器来实现的conn.addListener(new RedisPubSubAdapter<>(){@Overridepublic void message(String channel, String message){System.out.printf("从%s收到消息:%s\n", channel, message);}@Overridepublic void subscribed(String channel, long count){System.out.println("完成订阅" + count);}@Overridepublic void unsubscribed(String channel, long count){System.out.println("取消订阅" + count);}});// 订阅channelcmd.subscribe("c1", "c2");}public static void main(String[] args) throws Exception{Subscriper s = new Subscriper();s.init();s.subscribe();// 该程序就只订阅1minThread.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 定义RedisURIvar 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. 创建RedisClientthis.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. 创建RedisPubSubCommandsRedisPubSubCommands cmd = conn.sync();// 消息到来时,肯定是通过监听器来实现的conn.addListener(new RedisPubSubAdapter<>(){@Overridepublic void message(String channel, String message){System.out.printf("从%s收到消息:%s\n", channel, message);}@Overridepublic void subscribed(String channel, long count){System.out.println("完成订阅" + count);}@Overridepublic void unsubscribed(String channel, long count){System.out.println("取消订阅" + count);}});// 订阅channelcmd.subscribe("c2");}public static void main(String[] args) throws Exception{Subscriper2 s = new Subscriper2();s.init();s.subscribe();// 该程序就只订阅1minThread.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 定义RedisURIvar 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. 创建RedisClientthis.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. 创建RedisPubSubCommandsRedisPubSubCommands 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是被查询对象的全部信息。

相关文章:

Redis学习笔记Day01-Redis入门

声明&#xff1a;本博客部分内容是从终极SpringBoot讲义摘抄的&#xff0c;文字是OCR识别出来的&#xff0c;有可能存在识别错误的可能&#xff0c;如有错误&#xff0c;请大胆指正&#xff0c;我马上修改&#xff01; 目录 0.官方参考手册API1.连接命令2.key相关命令3.String命…...

C++ Lambda表达式的完整介绍

一、Lambda表达式概述 c在c11标准中引入了lambda表达式&#xff0c;一般用于定义匿名函数&#xff0c;lambda表达式&#xff08;也称为lambda函数&#xff09;是在调用或作为函数参数传递的位置处定义匿名函数对象的便捷方法。通常&#xff0c;lambda用于封装传递给算法或异步…...

【等保测评】云计算Linux服务器(一)

【等保测评】云计算&Linux服务器&#xff08;一&#xff09; 前言1、身份鉴别实例1实例2实例3实例4 2、访问控制实例1实例2实例3实例4实例5实例6实例7 前言 Linux是指UNIX克隆或类UNIX风格的操作系统&#xff0c;在源代码级别兼容绝大部分UNIX标准(IEEE POSIX, System V, …...

[vue-element-admin]下载与安装

一、环境搭建 1 nodejs 源码地址 sudo apt install build-essential # 内含gcc g make等全家桶git clone git://github.com/nodejs/node.git # 下载源码 cd node sudo ./config sudo make && make install # 编译 node -v # 查看是否编译成功二、遇见的问题 问题…...

OPENCV C++(九)鼠标响应+dft+idft

鼠标响应回调函数&#xff08;固定格式&#xff09; void on_mouse(int EVENT, int x, int y, int flags, void* userdata) {Mat hh;hh *(Mat*)userdata;Point p(x, y);switch (EVENT){case EVENT_LBUTTONDOWN:{points.x x;points.y y;mousePoints.push_back(points);circle…...

python编程求出介于这两个数 之间的所有质数并打印输出。显示格式为“*数是质数

这里写自定义目录标题 练习 &#xff1a;提示用户输入两个正整数&#xff0c;编程求出介于这两个数之间的所有质数并打印输出。显示格式为“*数是质数。”代码打印效果 练习 &#xff1a;提示用户输入两个正整数&#xff0c;编程求出介于这两个数之间的所有质数并打印输出。显示…...

基于Selenium模块实现无界面模式 执行JS脚本

此篇文章主要介绍如何使用 Selenium 模块实现 无界面模式 & 执行JS脚本(把滚动条拉到底部)&#xff0c;并以具体的示例进行展示。 1、Selenium 设置无界面模式 创建浏览器对象之前&#xff0c;创建 options 功能对象 &#xff1a;options webdriver.ChromeOptions() 添加…...

【LangChain学习】基于PDF文档构建问答知识库(二)创建项目

这里我们使用到 fastapi 作为项目的web框架&#xff0c;它是一个快速&#xff08;高性能&#xff09;的 web 框架&#xff0c;上手简单。 一.创建 FastAPI 项目 我们在IDE中&#xff0c;左侧选择 FastAPI &#xff0c;右侧选择创建一个新的虚拟环境。 创建成功&#xff0c;会有…...

【Kubernetes】Kubernetes之kubectl详解

kubectl 一、陈述式资源管理1. 陈述式资源管理方法2. 基本信息查看3. 项目周期管理3.1 创建 kubectl create 命令3.2 发布 kubectl expose命令3.3 更新 kubectl set3.4 回滚 kubectl rollout3.5 删除 kubectl delete 4. kubectl 的发布策略4.1 蓝绿发布4.2 红黑发布4.3 灰度发布…...

【torch.nn.PixelShuffle】和 【torch.nn.UnpixelShuffle】

文章目录 torch.nn.PixelShuffle直观解释官方文档 torch.nn.PixelUnshuffle直观解释官方文档 torch.nn.PixelShuffle 直观解释 PixelShuffle是一种上采样方法&#xff0c;它将形状为 ( ∗ , C r 2 , H , W ) (∗, C\times r^2, H, W) (∗,Cr2,H,W)的张量重新排列转换为形状为…...

Rocky9 KVM网桥的配置

KVM的默认网络模式为NAT,借助宿主机模式上网,现在我们来改成桥接模式,这样外界就可以直接和宿主机里的虚拟机通讯了。 Bridge方式即虚拟网桥的网络连接方式,是客户机和子网里面的机器能够互相通信。可以使虚拟机成为网络中具有独立IP的主机。 桥接网络(也叫物理设备共享…...

爬虫013_函数的定义_调用_参数_返回值_局部变量_全局变量---python工作笔记032

然后再来看函数,可以避免重复代码 可以看到定义函数以及调用函数...

将.doc文档的默认打开方式从WPS修改为word office打开方式的具体方法(以win 10 操作系统为例)

将.doc文档的默认打开方式从WPS修改为word office打开方式的具体方法&#xff08;以win 10 操作系统为例&#xff09; 随着近几年WPS软件的不断完善和丰富&#xff0c;在某些方面取得了具有特色的优势。在平时编辑.doc文档时候也常常用到wps软件&#xff0c;不过WPS文献也存在…...

如何搭建个人的GPT网页服务

写在前面 在创建个人的 GPT网页之前&#xff0c;我登录了 Git 并尝试了一些开源项目&#xff0c;但是没有找到满足我个性化需求的设计。虽然许多收费的 GPT网页提供了一些免费额度&#xff0c;足够我使用&#xff0c;但是公司的安全策略会屏蔽这些网页。因此&#xff0c;我决定…...

[QCM6125][Android13] 默认关闭SELinux权限

文章目录 开发平台基本信息问题描述解决方法 开发平台基本信息 芯片: QCM6125 版本: Android 13 kernel: msm-4.14 问题描述 正常智能硬件设备源码开发&#xff0c;到手的第一件事就是默认关闭SELinux权限&#xff0c;这样能够更加方便于调试功能。 解决方法 --- a/QSSI.1…...

【jvm】jvm发展历程

目录 一、Sun Classic VM二、Exact VM三、HotSpot VM四、JRockit五、J9六、KVM、CDC、CLDC七、Azul VM八、Liquid VM九、Apache Harmony十、Microsoft JVM十一、Taobao JVM十二、Dalvik VM 一、Sun Classic VM 1.1996年java1.0版本&#xff0c;sun公司发布了sun classic vm虚拟…...

Dubbo3.0 Demo

将SpringBoot工程集成Dubbo 1.创建父工程 2.创建子工程consumer&#xff0c;provider 3.初始化工程 4.引入依赖 在provider和consumer中引入dubbo依赖 <dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-spring-boot-starter</a…...

源码分析——ConcurrentHashMap源码+底层数据结构分析

文章目录 1. ConcurrentHashMap 1.71. 存储结构2. 初始化3. put4. 扩容 rehash5. get 2. ConcurrentHashMap 1.81. 存储结构2. 初始化 initTable3. put4. get 3. 总结 1. ConcurrentHashMap 1.7 1. 存储结构 Java 7 中 ConcurrentHashMap 的存储结构如上图&#xff0c;Concurr…...

R语言中的函数25:paste,paste0

文章目录 介绍paste0()实例 paste()实例 介绍 paste0()和paste()函数都可以实现对字符串的连接&#xff0c;paste0是paste的简化版。 paste0() paste (..., sep " ", collapse NULL, recycle0 FALSE)… one or more R objects, to be converted to character …...

(八)穿越多媒体奇境:探索Streamlit的图像、音频与视频魔法

文章目录 1 前言2 st.image&#xff1a;嵌入图像内容2.1 图像展示与描述2.2 调整图像尺寸2.3 使用本地文件或URL 3 st.audio&#xff1a;嵌入音频内容3.1 播放音频文件3.2 生成音频数据播放 4 st.video&#xff1a;嵌入视频内容4.1 播放视频文件4.2 嵌入在线视频 5 结语&#x…...

脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)

一、数据处理与分析实战 &#xff08;一&#xff09;实时滤波与参数调整 基础滤波操作 60Hz 工频滤波&#xff1a;勾选界面右侧 “60Hz” 复选框&#xff0c;可有效抑制电网干扰&#xff08;适用于北美地区&#xff0c;欧洲用户可调整为 50Hz&#xff09;。 平滑处理&…...

Docker 运行 Kafka 带 SASL 认证教程

Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明&#xff1a;server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...

跨链模式:多链互操作架构与性能扩展方案

跨链模式&#xff1a;多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈&#xff1a;模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展&#xff08;H2Cross架构&#xff09;&#xff1a; 适配层&#xf…...

基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解

JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用&#xff0c;结合SQLite数据库实现联系人管理功能&#xff0c;并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能&#xff0c;同时可以最小化到系统…...

Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档&#xff09;&#xff0c;如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下&#xff0c;风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...

20个超级好用的 CSS 动画库

分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码&#xff0c;而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库&#xff0c;可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画&#xff0c;可以包含在你的网页或应用项目中。 3.An…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)

本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

QT开发技术【ffmpeg + QAudioOutput】音乐播放器

一、 介绍 使用ffmpeg 4.2.2 在数字化浪潮席卷全球的当下&#xff0c;音视频内容犹如璀璨繁星&#xff0c;点亮了人们的生活与工作。从短视频平台上令人捧腹的搞笑视频&#xff0c;到在线课堂中知识渊博的专家授课&#xff0c;再到影视平台上扣人心弦的高清大片&#xff0c;音…...

二维FDTD算法仿真

二维FDTD算法仿真&#xff0c;并带完全匹配层&#xff0c;输入波形为高斯波、平面波 FDTD_二维/FDTD.zip , 6075 FDTD_二维/FDTD_31.m , 1029 FDTD_二维/FDTD_32.m , 2806 FDTD_二维/FDTD_33.m , 3782 FDTD_二维/FDTD_34.m , 4182 FDTD_二维/FDTD_35.m , 4793...

聚六亚甲基单胍盐酸盐市场深度解析:现状、挑战与机遇

根据 QYResearch 发布的市场报告显示&#xff0c;全球市场规模预计在 2031 年达到 9848 万美元&#xff0c;2025 - 2031 年期间年复合增长率&#xff08;CAGR&#xff09;为 3.7%。在竞争格局上&#xff0c;市场集中度较高&#xff0c;2024 年全球前十强厂商占据约 74.0% 的市场…...