Redis的基本使用和SpringBoot集成Redis

1.Redis简介

(1)什么是Redis
①Redis是一个基于内存的key-value结构数据库
②基于内存存储,读写性能高
③适合存储热点数据(热点商品、资讯、新闻)
④Redis是一个开源的内存中的数据结构存储系统,它可以用作:数据库、缓存和消息中间件
⑤它存储的value类型比较丰富,也被称为结构化的NoSql数据库。NoSql,不仅仅是SQL,泛指非关系型数据库。NoSql数据库
并不是要取代关系型数据库,而是关系型数据库的补充。
(2)Redis应用场景
①缓存
②任务队列
③消息队列
④分布式锁
(3)Redis默认有16个数据库,类似数组下标从0开始,初始默认用0号库
①使用命令 select <dbid>来切换数据库。如select 8
②统一密码管理,所有库使用统一密码
③dbsize :查看当前数据库的key的数量
④flushdb:清空当前库
⑤通杀全部库
(4)Redis是单线程+多路IO复用技术
多路复用是指使用一个线程来检查多个文件描述符(Socket)的就绪状态,比如调用select和poll函数,传入多个文件描述符,如果有一个文件描述符就绪,则返回,否则阻塞直到超时。得到就绪状态后进行真正的操作可以在同一个线程里执行,也可以启动线程执行(比如使用线程池)
与Memcache的三点不同:支持多数据类型,支持持久化,单线程+多路复用

1.1 SQL和NoSQL

在这里插入图片描述

(1)BASE:基本可用(BA)、软状态(S)、最终一致性(E)
①基本可用(Basically Available):
NoSQL允许分布式系统中某些部分出现故障,那么系统的其余部分依然可用。它不会像ACID那样,在系统出现故障时,进行强制拒绝,允许继续部分访问。
②软状态(Soft State):
NoSQL在数据处理过程中,允许这个过程,存在数据状态暂时不一致的情况。但经过纠错处理,最终会一致的。
③最终一致性(Eventually Consistent):
NoSQL的软状态允许数据处理过程的暂时不一致,但是最终处理结果将是一致的,说明NoSQL对数据处理过程可以有短暂的时间间隔,也允许分更细的步骤一个一个地处理,最好数据达到一致即可。这在互联网上进行分布式应用具有其明显的优势。
(2)存储方式

  • 关系型数据库基于磁盘进行存储,会有大量的磁盘IO,对性能有一定影响
  • 非关系型数据库,他们的操作更多的是依赖于内存来操作,内存的读写速度会非常快,性能自然会好一些

(3) 扩展性

  • 关系型数据库集群模式一般是主从,主从数据一致,起到数据备份的作用,称为垂直扩展。
  • 非关系型数据库可以将数据拆分,存储在不同机器上,可以保存海量数据,解决内存大小有限的问题。称为水平扩展。
  • 关系型数据库因为表之间存在关联关系,如果做水平扩展会给数据查询带来很多麻烦

1.2 键(key)

①keys * 查看当前库所有key
②exists key 判断某个key是否存在
③type key 查看你的key是什么类型
④del key 删除指定的key数据
⑤unlink key 根据value选择非阻塞删除(仅将key从keyspace元数据中删除,真正的删除会在后续异步操作)
⑥expire key 时间(时间单位:秒,为给定的key设置过期时间)
⑦ttl key 查看还有多少秒过期,-1表示永不过期,-2表示已过期
注意:Redis 重新set,会导致之前的expire的时间失效(被重置掉)

2.Redis十大数据类型

Redis是典型的key-value数据库,key一般是字符串,而value包含很多不同的数据类型:
在这里插入图片描述

2.1 String类型

(1)String类型,也就是字符串类型,是Redis中最简单的存储类型。
其value是字符串,不过根据字符串的格式不同,又可以分为3类:
①string:普通字符串
②int:整数类型,可以做自增、自减操作
③float:浮点类型,可以做自增、自减操作
(2)不管是哪种格式,底层都是字节数组形式存储,只不过是编码方式不同。字符串类型的最大空间不能超过512M
(3)String类型是二进制安全的,意味着Redis的String可以包含任何数据。比如jpg图片或者序列化的对象
(4)String的数据结构为简单动态字符串(Simple Dynamic String,缩写SDS).是可以修改的字符串,内部结构实现上类似于Java的ArrayList,采用预分配冗余空间的方式来减少内存的频繁分配
(5)String的常见命令有:
①SET:添加或者修改已经存在的一个String类型的键值对
set key value //设置指定key的值
②GET:根据key获取String类型的value
get key // 获取指定key的值
③MSET:批量添加多个String类型的键值对
mset key1 value1 key2 value2 … // 同时设置一个或多个 key-value
④MGET:根据多个key获取多个String类型的value
mget key1 value1 key2 value2 … // 同时获取一个或多个 key-value
⑤INCR:让一个整型的key自增1
incr key 将key中存储的数字值增1,只能对数字值操作,如果为空,新增值为1
补充:INCRBY:让一个整型的key自增并指定步长,例如:incrby num 2 // 让num值自增2
⑥INCRBYFLOAT:让一个浮点类型的数字自增并指定步长
⑦SETNX:添加一个String类型的键值对,前提是这个key不存在,否则不执行
setnx key value // 只有在key不存在时设置 key 的值
补充:msetnx key1 value1 key2 value2 …
//同时设置一个或多个key-value对,当且仅当所有给定key都不存在(原子性,有一个失败则都失败)
⑧SETEX:添加一个String类型的键值对,并且指定有效期
setex key 过期时间 value // 设置指定key的值,并将key的过期时间设为 seconds 秒
⑨strlen key 获得值的长度
⑩decr key 将key中存储的数字值减1
补充:incr key 对存储在指定key的数值执行原子的加1操作
所谓原子操作是指不会被线程调度机制打断的操作,这种操作一旦开始,就一直运行到结束,中间不会
有任何 context switch(切换到另一个线程)
1.在单线程中,能够在单条指令中完成的操作都可以认为是“原子操作”,因为中断只能发生于指令之间
2.在多线程中,不能被其他进程(线程)打断的操作就叫原子操作。
Redis单命令的原子性主要得益于Redis的单线程
⑪getrange key 起始位置 结束位置
获得值的范围,类似于java中的subString(这里是 前包,后包)
⑫setrange key 起始位置 value
用value覆写key所存储的字符串值,从<起始位置>开始(索引从0开始)
⑬getset key value //以旧换新,设置了新值的同时获得旧值

2.2 列表list操作命令

(1)Redis中的List类型与Java中的LinkedList类似,可以看做是一个双向链表结构。既可以支持正向检索和也可以支持反向检索。
(2)特征也与LinkedList类似:常用来存储一个有序数据,例如:朋友圈点赞列表,评论列表等。
①有序
②元素可以重复
③插入和删除快
④查询速度一般
(3)Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部或者尾部。List的数据结构为快速链表quickList,首先在列表元素比较少的情况下会使用一块连续的内存存储,这个结构是ziplist,也就是压缩列表。它将所有的元素紧挨着一起存储,分配的是一块连续的内存。当数据量比较大时才会改成quicklist。因为普通的链表需要的附加指针空间太大,会比较浪费空间。Redis将链表和ziplist结合起来组成了quicklist。也就是将多个ziplist使用双向指针串起来使用。这样既满足了快速的插入删除性能,又不会出现太大的空间冗余。
(4)List的常见命令有:
①lpush/rpush key value1 value2 … // 将一个或多个值插入到列表头部/尾部
例如:lpush mylist a b c
②lrange key start stop //按照索引下标获得元素(从左到右)
例如:lrange mylist 0 -1 // 0 -1表示获取所有
③lpop/rpop key // 从左边/右边吐出一个值(值在键在,值光键亡)
④llen key // 获取列表长度
⑤brpop key1 key2 … timeout // 移出并获取列表的最后一个元素,或发现可弹出元素为止
//timeout 超时时间;列表没有元素,就会一直阻塞直到超时
⑥lindex key index 按照索引下标获得元素(从左到右)
在这里插入图片描述

2.3 集合set操作命令

Redis的set 是string类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。它的底层其实是一个
value为null的hash表,所以添加,删除,查找的复杂度都是O(1)
①sadd key member1 member2 … //向集合中添加一个或多个成员
②smembers key // 返回集合中的所有成员
③sismember key value // 判断集合key是否为含有该value值,有1,没有0
④scard key // 返回该集合的元素个数
⑤sinter key1 key2 … // 返回给定所有集合的交集
⑤sunion key1 key2 … // 返回所有给定集合的并集
⑥sdiff key1 key2 … // 返回给定所有集合的差集(key1中有的,不包含key2中的)
⑦srem key member1 member2 … // 移除集合中一个或多个成员
smove <souce> <destination> value // 把集合中一个值从一个集合移动到另一个集合
⑨spop key // 随机从该集合中吐出一个值

2.4 有序集合Zset(sorted set)操作命令

(1)Redis的SortedSet是一个可排序的set集合,与Java中的TreeSet有些类似,但底层数据结构却差别很大。SortedSet中的每一个元素都带有一个score属性,可以基于score属性对元素排序,底层的实现是一个跳表(SkipList)加 hash表。
(2)SortedSet具备下列特性:
①可排序
②元素不重复
③查询速度快
(3)Redis sorted set 有序集合是string类型元素的集合,且不允许重复的成员。每个元素都会关联一个double类型的分数(score)。redis正是通过分数来为集合中的成员进行从小到大排序。有序集合的成员是唯一的,但分数却可以重复。
(4)SortedSet的常见命令有:
①zadd key score1 member1 score2 member2 … // 向有序集合中添加一个或多个成员,或者更新已存在成员的分数
②zrange key start stop [WITHSCORS] // 通过索引区间返回有序集合中指定区间内的成员(withscors可以带分数一起返回)
③zincrby key increment member // 有序集合中对指定成员的分数加上增量 increment
④zrem key member [member …] // 移除有序集合中的一个或多个成员
(5)zset底层使用了两个数据结构:
①hash,hash的作用就是关联元素value和权重score,保障元素value的唯一性,可以通过元素value找到对应的score值。
②跳跃表,跳跃表的目的在于给元素value排序,根据score的范围获取元素列表

2.5 哈希 hash 操作命令

(1)Hash类型,也叫散列,其value是一个无序字典,类似于Java中的HashMap结构。
String结构是将对象序列化为JSON字符串后存储,当需要修改对象某个字段时很不方便:
在这里插入图片描述
(2)Hash结构可以将对象中的每个字段独立存储,可以针对单个字段做CRUD:

在这里插入图片描述
(3)Redis hash是一个String类型的filed和value的映射表,hash特别适合用于存储对象。hash类型对应的数据结构是两种:
ziplist(压缩列表),hashtable(哈希表)。当field-value长度较短且个数较少时,使用ziplist,否则使用hashtable
(4)Hash类型的常见命令
①hset key filed value // 将哈希表key中的字段field的值设为value
②hget key field // 获取哈希表中指定字段的值
③hdel key field // 删除存储在哈希表中的指定字段
④hkeys key // 获取哈希表中所有字段
⑤hvals key // 获取哈希表中所有值
⑥hgetall key // 获取在哈希表中指定key的所有字段和值
⑦HMSET:批量添加多个hash类型key的field的值
⑧HMGET:批量获取多个hash类型key的field的值
⑨HINCRBY:让一个hash类型key的字段值自增并指定步长
⑩HSETNX:添加一个hash类型的key的field值,前提是这个field不存在,否则不执行
在这里插入图片描述

2.6 Redis位图Bitmaps

(1)简介
现代计算机采用二进制(位)作为信息的基础单位,1个字节等于8位,例如“abc”字符串是由3个字节组成,但实际在计算机
存储时将其用二进制表示,“abc”分别对应的ASCII码分别是97、98、99,对应的二进制分别是01100001、01100010和
01100011。合理的使用操作位能够有效地提高内存使用率和开发效率。Redis提供了Bitmaps这个“数据类型”可以实现对
位的操作
①Bitmaps本身不是一种数据类型,它实际上就是字符串(key-value),但是它可以对字符串的位进行操作
②Bitmaps单独提供了一套命令,所以在Redis中使用Bitmaps和使用字符串的方法不太相同。可以把Bitmaps想象成一个
以位为单位的数组,数组的每个单位只能存储0和1,数组的下标在Bitmaps中叫做偏移量。
(2)Bitmaps是用String类型作为底层数据结构实现的一种统计二值状态的数据类型。位图本质是数组,它是基于String
数据类型的按位的操作。该数组由多个二进制位组成,每个二进制位都对应一个偏移量(我们称之为一个索引)。
Bitmap支持的最大位数是2^32位,
它可以极大的节约存储空间,使用512M内存就可以存储多达42.9亿的字节信息(2^32 = 4294967296)

(3)格式
①setbit key offset value // 设置Bitmaps中某个偏移量的值(0或1),偏移量offset从0开始
②getbit key offset // 获取Bitmaps中某个偏移量的值
③bitcount key start end // 统计字符串从start字节到end字节比特值为1的数量
④strlen:统计字节数占用多少,超过8位后自己按照8位一组一byte再扩容

在这里插入图片描述

⑤bitcount:全部键里面含有1的有多少个
在这里插入图片描述

在这里插入图片描述

2.7 Redis基数统计(HyperLogLog)

(1)什么是UV?
Unique Visitor,独立访客,一般理解为客户端IP
(2)HyperLogLog是什么?
在这里插入图片描述
(3)基数是什么?
是一种数据集,去除重复后的真实个数
在这里插入图片描述
(4)基数统计:用于统计一个集合中不重复的元素个数,就是对集合去重复后剩余元素的计算
(5)基本命令:
在这里插入图片描述

2.8Redis地理空间(CEO)

(1)核心思想
在这里插入图片描述
(2)命令

在这里插入图片描述

2.9 Redis流(Stream)

(1)Redis流是Redis版的MQ消息中间件+阻塞队列。Redis流实现了消息队列,支持消息的持久化、支持自动生成全局唯一ID、支持ack确认消息的模式、支持消息组模式等,让消息队列更加的稳定和可靠

2.10 Resdis位域

4.Redis的配置文件介绍

4.1 ###Units单位###

配置大小单位,开头定义了一些基本的度量单位,只支持 bytes,不支持 bit ,大小写不敏感

4.2 ###INCLUDES包含###

类似于jsp中的 include,多实例的情况可以把公用的配置文件提取出来

4.3 ###网络相关配置

(1)bind
默认情况下 bind = 127.0.0.1 只能接受本机的访问请求,不写的情况下,无限制接受任何ip地址的访问
(2)protected-mode
如果开启了protected-mode,那么在没有设定bind ip且没有设密码的情况下,Redis只允许接受本机的响应
(将本机访问保护模式设置no)
(3)Port:端口号,默认 6379
(4)tcp-backlog
①设置tcp的backlog,backlog其实是一个连接队列,backlog队列总和=未完成三次握手队列 + 已经完成
三次握手队列。
②在高并发环境下你需要一个高backlog值来避免慢客户端连接问题。
注意Linux内核会将这个值减小到/proc/sys/net/core/somaxconn的值(128),所以需要确认增大/proc/sys/net/core/somaxconn和/proc/sys/net/ipv4/tcp_max_syn_backlog(128)两个值来达到想要的效果
(5)timeout
一个空闲的客户端维持多少秒会关闭,0表示关闭该功能。即永不关闭。
(6)tcp-keepalive
①对访问客户端的一种心跳检测,每隔n秒检测一次。
②单位为秒,如果设置为0,则不会进行Keepalive检测,建议设置成60
③如果还活着继续提供服务,不活着就释放连接

4.4 ###GENERAL通用###

(1)daemonize
是否为后台进程,设置为yes。守护进程,后台启动
(2)pidfile
存放pid文件(存放进程号)的位置,每个实例会产生一个不同的pid文件
(3)loglevel
①指定日志记录级别,Redis总共支持四个级别:debug、verbose、notice、warning,默认为notice
②四个级别根据使用阶段来选择,生产环境选择notice 或者warning
(4)logfile:设置日志的输出文件路径,默认为空
(5)databases
设定库的数量 默认16,默认使用0号数据库,可以使用SELECT 命令在连接上指定数据库id

4.5. ###SECURITY安全###

(1)设置密码
①默认是没有密码的,设置密码可以把下面的注释打开
在这里插入图片描述
②在命令行中设置密码,只是临时的。重启redis服务器,密码就还原了。
在这里插入图片描述
③永久设置,需要在配置文件中进行配置

4.6 #### LIMITS限制

(1)maxclients
①设置redis同时可以与多少个客户端进行连接
②默认情况下为 10000 个客户端
③如果达到了此限制,redis则会拒绝新的连接请求,并且向这些连接请求方
发出“max number of clients reached”以作回应。
(2)maxmemory
①建议必须设置,否则,将内存占满,造成服务器宕机
②设置redis可以使用的内存量。一旦到达内存使用上限,redis将会试图移除内部数据,移除规则可以
通过maxmemory-policy来指定。
③如果redis无法根据移除规则来移除内存中的数据,或者设置了“不允许移除”,那么redis则会针对那些
需要申请内存的指令返回错误信息,比如SET、LPUSH等。
④但是对于无内存申请的指令,仍然会正常响应,比如GET等。如果你的redis是主redis(说明你的redis有从redis),
那么在设置内存使用上限时,需要在系统中留出一些内存空间给同步队列缓存,只有在你设置的是“不移除”的
情况下,才不用考虑这个因素。
(3)maxmemory-policy
①volatile-lru:使用LRU算法移除key,只对设置了过期时间的键;(最近最少使用)
②allkeys-lru:在所有集合key中,使用LRU算法移除key
④volatile-random:在过期集合中移除随机的key,只对设置了过期时间的键
⑤allkeys-random:在所有集合key中,移除随机的key
⑥volatile-ttl:移除那些TTL值最小的key,即那些最近要过期的key
⑦noeviction:不进行移除。针对写操作,只是返回错误信息
(4)maxmemory-samples
①设置样本数量,LRU算法和最小TTL算法都并非是精确的算法,而是估算值,所以你可以设置样本的大小,redis默认
会检查这么多个key并选择其中LRU的那个。
②一般设置3到7的数字,数值越小样本越不准确,但性能消耗越小

5.Redis的发布和订阅

5.1 什么是发布和订阅

(1)Redis发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息
(2)Redis客户端可以订阅任意数量的频道
在这里插入图片描述

5.2 发布订阅命令行实现

(1)打开一个客户端订阅 channel1
subscribe channel1
(2)打开另一个客户端,给channel1发布消息hello
publish channel1 hello // 返回的1是订阅者数量
(3)打开第一个客户端可以看到发送的消息
注:发布的信息没有持久化,如果在订阅的客户端收不到hello,只能收到订阅后发布的信息

6.SpringBoot集成Redis

6.1 集成Jedis

(1)Jedis是什么?
Jedis Client是Redis官网推荐的一个面向Java客户端,库文件实现了对各类API进行封装调用
(2)集成Jedis的步骤
①导入相关坐标

  <!--   Jedis坐标   -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.8.1</version>
        </dependency>

(2)相关实例

public class JedisTest {
    @Test
    public void testJedis() {
//        1.获取连接
        Jedis jedis = new Jedis("localhost", 6379);
//        2.执行具体的操作
        jedis.set("username","lisi");
        String value = jedis.get("username");
        System.out.println(value);
//        3.关闭连接
        jedis.close();
    } }

6.1.1 Jedis连接池

(1)Jedis本身是线程不安全的,并且频繁的创建和销毁连接会有性能损耗,因此我们推荐大家使用Jedis连接池代替Jedis的直连方式
(2)创建Jedis的连接池

public class JedisConnectionFacotry {
     private static final JedisPool jedisPool;
     static {
         //配置连接池
         JedisPoolConfig poolConfig = new JedisPoolConfig();
         poolConfig.setMaxTotal(8);
         poolConfig.setMaxIdle(8);
         poolConfig.setMinIdle(0);
         poolConfig.setMaxWaitMillis(1000);
         //创建连接池对象
         jedisPool = new JedisPool(poolConfig,
                 "192.168.150.101",6379,1000,"123321");
     }
     public static Jedis getJedis(){
          return jedisPool.getResource();
     }
}

(3)代码说明:
①JedisConnectionFacotry:工厂设计模式是实际开发中非常常用的一种设计模式,我们可以使用工厂,去降低代的耦合,比如Spring中的Bean的创建,就用到了工厂设计模式
②静态代码块:随着类的加载而加载,确保只能执行一次,我们在加载当前工厂类的时候,就可以执行static的操作完成对 连接池的初始化
③最后提供返回连接池中连接的方法
(4)在我们完成了使用工厂设计模式来完成代码的编写之后,我们在获得连接时,就可以通过工厂来获得。,而不用直接去new对象,降低耦合,并且使用的还是连接池对象。当我们使用了连接池后,当我们关闭连接其实并不是关闭,而是将Jedis还回连接池的。

    @BeforeEach
    void setUp(){
        //建立连接
        /*jedis = new Jedis("127.0.0.1",6379);*/
        jedis = JedisConnectionFacotry.getJedis();
         //选择库
        jedis.select(0);
    }
   @AfterEach
    void tearDown() {
        if (jedis != null) {
            jedis.close();
        }
    }

6.2 集成lettuce

(1)lettuce是什么?
在这里插入图片描述
(2)Jedis和Lettuce的区别
在这里插入图片描述

(3)步骤
①pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.atguigu.redis7</groupId>
    <artifactId>redis7_study</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.10</version>
        <relativePath/>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <junit.version>4.12</junit.version>
        <log4j.version>1.2.17</log4j.version>
        <lombok.version>1.16.18</lombok.version>
    </properties>

    <dependencies>
        <!--SpringBoot通用依赖模块-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--jedis-->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>4.3.1</version>
        </dependency>
        <!--lettuce-->
        <dependency>
            <groupId>io.lettuce</groupId>
            <artifactId>lettuce-core</artifactId>
            <version>6.2.1.RELEASE</version>
        </dependency>
        <!--通用基础配置-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>${log4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
            <optional>true</optional>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

②案例

@Slf4j
public class LettuceDemo{
    public static void main(String[] args) {
        //使用构建器 RedisURI.builder
        RedisURI uri = RedisURI.builder()
                .redis("192.168.111.181")
                .withPort(6379)
                .withAuthentication("default","111111")
                .build();
        //创建连接客户端
        RedisClient client = RedisClient.create(uri);
        StatefulRedisConnection conn = client.connect();
        //操作命令api
        RedisCommands<String,String> commands = conn.sync();

        //keys
        List<String> list = commands.keys("*");
        for(String s : list) {
            log.info("key:{}",s);
        }
        //String
    commands.set("k1","1111");
    String s1 = commands.get("k1");
    System.out.println("String s ==="+s1);

        //list
    commands.lpush("myList2", "v1","v2","v3");
    List<String> list2 = commands.lrange("myList2", 0, -1);
    for(String s : list2) {
     System.out.println("list ssss==="+s);
    }
    //set
    commands.sadd("mySet2", "v1","v2","v3");
    Set<String> set = commands.smembers("mySet2");
    for(String s : set) {
     System.out.println("set ssss==="+s);
    }
    //hash
    Map<String,String> map = new HashMap<>();
        map.put("k1","138xxxxxxxx");
        map.put("k2","atguigu");
        map.put("k3","zzyybs@126.com");//课后有问题请给我发邮件

    commands.hmset("myHash2", map);
    Map<String,String> retMap = commands.hgetall("myHash2");
    for(String k : retMap.keySet()) {
     System.out.println("hash  k="+k+" , v=="+retMap.get(k));
    }

    //zset
    commands.zadd("myZset2", 100.0,"s1",110.0,"s2",90.0,"s3");
    List<String> list3 = commands.zrange("myZset2",0,10);
    for(String s : list3) {
     System.out.println("zset ssss==="+s);
    }

    //sort
    SortArgs sortArgs = new SortArgs();
    sortArgs.alpha();
    sortArgs.desc();

    List<String> list4 = commands.sort("myList2",sortArgs);
    for(String s : list4) {
     System.out.println("sort ssss==="+s);
    }

        //关闭
        conn.close();
        client.shutdown();
    }
}

6.3 在Spring Boot项目使用Spring Data Redis操作Redis

(1)SpringData是Spring中数据操作的模块,包含对各种数据库的集成,其中对Redis的集成模块就叫做SpringDataRedis
(2)SpringDataRedis中提供了RedisTemplate工具类,其中封装了各种对Redis的操作。并且将不同数据类型的操作API封装到了不同的类型中:

在这里插入图片描述
(3)导入相关坐标

<!--Redis依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--连接池依赖-->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>

(4)Redis相关配置

spring:
# Redis相关配置
  redis:
    host: localhost
    port: 6379
    database: 0 # 默认有16个数据库,操作的是第0号数据库
    jedis:
# Redis连接池配置
      pool:
        max-active: 8 # 最大连接数
        max-wait: 1ms # 连接池最大阻塞等待时间
        max-idle: 14 # 连接池中的最大空闲连接
        min-idle: 0 # 连接池中的最小空闲连接

(5)实例

@SuppressWarnings("all")
@SpringBootTest(classes = SsmMangerApplication.class)
@RunWith(SpringRunner.class)
public class SpringDataRedisTest {
    @Autowired
    private RedisTemplate redisTemplate; //注入RedisTemplate

    //操作String类型数据
    @Test
    public void testString() {
        redisTemplate.opsForValue().set("city", "beijing");
        Object city = redisTemplate.opsForValue().get("city");
        System.out.println(city);
    }
    //    操作Hash类型数据
    @Test
    public void testHash() {
        HashOperations hashOperations = redisTemplate.opsForHash();
//        存值
        hashOperations.put("002", "name", "xaioming");
        hashOperations.put("002", "age", "20");
        hashOperations.put("002", "address", "bj");
//        取值
        String age = (String) hashOperations.get("002", "age");
        System.out.println(age);
//        获得hash结构中的所有字段
        Set keys = hashOperations.keys("002");
        for (Object key : keys) {
            System.out.println(key);
//            获得hash结构中的所有值
            List values = hashOperations.values("002");
            for (Object value : values) {
                System.out.println(value);
            } } }
    //操作List类型的数据
    @Test
    public void testList() {
        ListOperations listOperations = redisTemplate.opsForList();
//        存值
        listOperations.leftPush("mylist", "a");
        listOperations.leftPushAll("mylist", "b", "c", "d");
//        取值
        List<String> mylist = listOperations.range("mylist", 0, -1);
        for (String value : mylist) {
            System.out.println(value);
        }
//        出队列
        Object element = listOperations.rightPop("mylist");
        System.out.println(element);
    }

    //    操作set类型的数据
    @Test
    public void testSet() {
        SetOperations setOperations = redisTemplate.opsForSet();
//        存值
        setOperations.add("myset", "a", "b", "c", "a");
//        取值
        Set<String> myset = setOperations.members("myset");
        for (String o : myset) {
            System.out.println(o);
        }
//      删除成员
        setOperations.remove("myset", "a", "b");
//        取值
        myset = setOperations.members("myset");
        for (String o : myset) {
            System.out.println(o);

        }
    }

    //    操作ZSet类型的数据
    @Test
    public void testZSet() {
        ZSetOperations zSetOperations = redisTemplate.opsForZSet();
//        存值
        zSetOperations.add("myZset", "a", 10.0);
        zSetOperations.add("myZset", "b", 11.0);
        zSetOperations.add("myZset", "c", 12.0);
        zSetOperations.add("myZset", "a", 13.0);

//                取值
        Set<String> myZSet = zSetOperations.range("myZset", 0, -1);
        for (String s : myZSet) {
            System.out.print(s);//bca
        }

//                修改分数
        zSetOperations.incrementScore("myZset", "b", 20.0);

//                取值

        myZSet = zSetOperations.range("myZset", 0, -1);
        System.out.println();
        for (String s : myZSet) {
            System.out.print(s);//cab
        }
//                删除成员
        zSetOperations.remove("myZset", "a", "b");
//        取值
        myZSet = zSetOperations.range("myZset", 0, -1);
        System.out.println();
        for (String s : myZSet) {
            System.out.print(s);//c
        }
    }

//    通用操作
    @Test
    public void testCommon(){
//        获取Redis中所有的key

        Set<String> keys = redisTemplate.keys("*");
        for (String key : keys) {
            System.out.print(key);
        }
//        判断某个key是否存在
        Boolean haha = redisTemplate.hasKey("haha");
        System.out.println(haha);

//        删除指定key
        redisTemplate.delete("myZset");

//        获取指定key对应的value的数据类型
        DataType dataType = redisTemplate.type("myset");
        System.out.println(dataType.name());
    } }

(6)SpringDataRedis的序列化方式
①RedisTemplate可以接收任意Object作为值写入Redis,只不过写入前会把Object序列化为字节形式,默认是采用JDK序列化,得到的结果是这样的
在这里插入图片描述
②缺点:可读性差、内存占用较大
③我们可以自定义RedisTemplate的序列化方式,代码如下:

@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
        throws UnknownHostException {
    // 创建Template
    RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
    // 设置连接工厂
    redisTemplate.setConnectionFactory(redisConnectionFactory);
    // 设置序列化工具
    GenericJackson2JsonRedisSerializer jsonRedisSerializer = 
					new GenericJackson2JsonRedisSerializer();
    // key和 hashKey采用 string序列化
    redisTemplate.setKeySerializer(RedisSerializer.string()); 
    redisTemplate.setHashKeySerializer(RedisSerializer.string());
    // value和 hashValue采用 JSON序列化
    redisTemplate.setValueSerializer(jsonRedisSerializer);
    redisTemplate.setHashValueSerializer(jsonRedisSerializer);
    return redisTemplate;
}

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值