当前位置 博文首页 > BWH_Steven:【1w字+干货】第一篇,基础:让你的 Redis 不再只是

    BWH_Steven:【1w字+干货】第一篇,基础:让你的 Redis 不再只是

    作者:BWH_Steven 时间:2021-01-25 10:52

    【1w字+干货】第一篇,基础:让你的 Redis 不再只是安装吃灰到卸载(Linux环境)

    Redis 基础以及进阶的两篇已经全部更新好了,为了字数限制以及阅读方便,分成两篇发布。

    本篇主要内容为:NoSQL 引入 Redis ,以及在 Linux7 环境下的安装,配置,以及总结了非常详细的类型,用法以及例子,最后通过 Jedis 以及 Springboot 中的 RedisTemplate 在 IDEA 中远程操作
    Redis。

    第二篇会主要涉及到配置文件,发布订阅,主从复制,哨兵等一些进阶用法的一个基本使用。

    一 简述 NoSQL

    Redis是一个使用ANSI C编写的开源、支持网络、基于内存、可选持久性的键值对存储数据库 ——维基百科

    可以简单的说,Redis就是一款高性能的NoSQL数据库

    (一) 什么是NoSQL?

    我们前面所学习的MySQL数据库是典型的的SQL数据库也就是传统的关系型数据库,而我们今天学习的Redis数据库则是一款NoSQL数据库,也叫作非关系型数据库,它与我们熟悉的MySQL等的概念完全是不一样的,它是一项全新的数据库理念,我们帖一组百度百科的解释

    NoSQL,泛指非关系型的数据库。随着互联网web2.0网站的兴起,传统的关系数据库在处理web2.0网站,特别是超大规模和高并发的SNS类型的web2.0纯动态网站已经显得力不从心,出现了很多难以克服的问题,而非关系型的数据库则由于其本身的特点得到了非常迅速的发展。NoSQL数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,尤其是大数据应用难题 ——百度百科

    说明:我们现在所看到的的博客,RSS,P2P,微博,抖音等均属于 Web2.0的产物,Web2.0相比较过去的Web1.0更加注重于用户的交互,用户不仅可以浏览,还可以上传一些资源到网站上,例如图片文字或者说短视频等,使得用户也参与到了网站内容的制造中去了

    (二) 为什么使用NoSQL?

    • 部署成本低:部署操作简单,以开源软件为主

    • 存储格式丰富:支持 key-value形式、文档、图片等众多形式,包括对象或者集合等格式

    • 速度快:数据存储在缓存中,而不是硬盘中,而且例如Redis基于键值对,同时不需要经过SQL层解析,性能非常高

    • 无耦合性,易扩展

      • 在SQL中,一个正在使用的数据是不允许删除的,但NoSQL却可以操作

    (三) NoSQL可以替代SQL吗?

    有人会说,NoSQL = Not SQL ,但是我更倾向这样理解 NoSQL = Not only SQL ,我们不能以一个绝对的结论来判定两项技术的好坏,每一项技术的产生都有其特定的原因,在我看来,NoSQL更适合作为SQL数据库的补充,由于海量数据的出现,性能的要求高了起来,而NoSQL这种产物,对于结构简单但是数据量大的数据处理起来要比传统的SQL快很多,但是同样的,其逻辑运算就必须很简单,否则它也是力不从心的

    在我看来,可以简单的说,NoSQL就是以功能换取性能,但是需要处理复杂的业务逻辑还需要使用关系型数据库,所以说想要在模型中完全用NoSQL替代SQL是不现实的,两者更像是互补的关系

    SQL的好处:

    1. 支持在一个表以及多表之前进行复杂的查询操作
    2. 支持对事物的处理,能保证数据的安全要求
    3. 学习成本低,资料较多

    市面上的NoSQL产品非常多,我们今天所要介绍的就是其中一款基于键值存储的数据库——Redis

    (四)NoSQL数据库的四大分类表格分析

    分类 Examples举例 典型应用场景 数据模型 优点 缺点
    键值(key-value) Tokyo Cabinet/Tyrant, Redis, Voldemort, Oracle BDB 内容缓存,主要用于处理大量数据的高访问负载,也用于一些日志系统等等。 Key 指向 Value 的键值对,通常用hash table来实现 查找速度快 数据无结构化,通常只被当作字符串或者二进制数据
    列存储数据库 Cassandra, HBase, Riak 分布式的文件系统 以列簇式存储,将同一列数据存在一起 查找速度快,可扩展性强,更容易进行分布式扩展 功能相对局限
    文档型数据库 CouchDB, MongoDb Web应用(与Key-Value类似,Value是结构化的,不同的是数据库能够了解Value的内容) Key-Value对应的键值对,Value为结构化数据 数据结构要求不严格,表结构可变,不需要像关系型数据库一样需要预先定义表结构 查询性能不高,而且缺乏统一的查询语法。
    图形(Graph)数据库 Neo4J, InfoGrid, Infinite Graph 社交网络,推荐系统等。专注于构建关系图谱 图结构 利用图结构相关算法。比如最短路径寻址,N度关系查找等 很多时候需要对整个图做计算才能得出需要的信息,而且这种结构不太好做分布式的集群方案。

    二 初识Redis

    (一) 什么是 Redis

    我们在一开始提到了,Redis就是一款高性能的NoSQL数据库,那么它的应用场景是什么呢?

    • 用于用户内容缓存,可以处理大量数据的高访问负载,例如:数据查询,新闻,商品内容

    • 任务队列,例如:秒杀,12306

    • 在线好友列表

    • 应用、网站访问统计排行

    由于其基于键值存储,那么可以支持的存储的类型有什么呢?

    • 字符串类型 - String

    • 列表 - list:linkedlist

    • 集合 - set

    • 有序集合 - sortedset

    • 哈希 - hash:map

    (二)下载安装

    说明:

    推荐使用 Linux 进行部署,所以我们后面也会详细介绍 Linux 中的安装配置方式,但是如果只是想快速学习语法,也可以勉强使用 Windows 版本,安装会简单很多。

    Redis is written in ANSI C and works in most POSIX systems like Linux, *BSD, and OS X, without external dependencies. Linux and OS X are the two operating systems where Redis is developed and tested the most, and we recommend using Linux for deployment . Redis may work in Solaris-derived systems like SmartOS, but the support is best effort. There is no official support for Windows builds.

    官网说明地址:https://redis.io/topics/introduction

    (1) linux 推荐

    官网:https://redis.io(推荐)

    • 访问可能较慢

    中文网:http://www.redis.net.cn

    • 版本有一些滞后,例如官网已经 6.0.9 了,中文网首页仍挂着 5.0.4

    A:下载

    # 下载 redis-6.0.9 压缩包
    wget http://download.redis.io/releases/redis-6.0.9.tar.gz 
    

    补充:

    • 可以通过 http://download.redis.io/releases 查看选择需要的版本
    • 此方式下载后的压缩文件位于 /home 目录下

    B:解压

    一般来说,我们程序都会放在 /opt 目录下,所以我们先将这个压缩文件移动过去再解压

    # 移动此文件到根目录下的 opt 目录中
    mv redis-6.0.9.tar.gz /opt
    # 解压此文件
    tar -zxvf redis-6.0.9.tar.gz
    

    解压后 opt 目录下就多出一个 redis-6.0.9 的文件夹,我们打开它,就可以看到一些文件在其中,其中 redis.conf 是我们一会要用的配置文件,暂时先不理会

    解压后的文件貌似也不能运行啊,这是当然的,因为这些文件还没有经过编译和安装,在编译之前,首先要检查一下 GCC 的版本

    C:检查 GCC 版本(Redis 6 以下可以忽略)

    如果你选择的是 Redis 6 以上的版本,例如这里选择的 6.0.9,你的 gcc 版本如果太低就会导致后面编译出错,最起码你的 gcc 要到 5.3 的版本以上

    如果没有 gcc 先进行安装

    yum -y install gcc
     
    yum -y install gcc-c++
    

    安装完成后,通过 gcc -v 查看到安装到的版本是 4.x.x 版本的,所以要升级,旧版本的 Redis 可以不去做升级这一步

    依次执行下面每一条命令

    # 升级到gcc 9.3
    yum -y install centos-release-scl
    yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils
    
    # scl命令启用只是临时的,退出shell或重启就会恢复原系统gcc版本
    scl enable devtoolset-9 bash
    
    # 长期使用 gcc 9.3 还需要进行如下操作
    echo "source /opt/rh/devtoolset-9/enable" >>/etc/profile
    source /etc/profile
    

    查看一下更新后的版本

    D:编译安装

    依次执行编译和安装,

    # 编译
    make
    
    # 安装
    make install
    

    make 会慢一下,耐心等待一下,如果出了错误,一般都是 gcc 的问题

    安装后的内容一般都在 /usr/local/bin

    E:拷贝配置文件

    我们把原来的配置文件就放在那个解压文件中,我们自己用的,单独复制一份出来,方便我们操作和更改

    我们先去 /usr/local/bin 中创建一个新的文件夹,然后把之前解压后的文件夹中的 redis.conf 拷贝过来

    # 跳转到指定目录下
    cd /usr/local/bin
    # 新建一个文件夹
    mkdir myconfig
    # 复制 /opt/redis-6.0.9/redis.conf 到 当前目录的 myconfig 文件夹下
    cp /opt/redis-6.0.9/redis.conf myconfig
    

    看一下过程

    F:开启后台运行

    为了保证我们的redis可以后台运行,我们去编辑拷贝过来的 redis.conf 配置文件

    vim redis.conf
    

    在其中找到 daemonize no

    将 no 修改为 yes,保存退出

    G:运行 Redis

    下面先运行一下其服务端(保证当前在 usr/local/bin 目录下)

    # 运行服务端
    redis-server myconfig/redis.conf
    
    • 加 myconfig/redis.conf 就是为了制定其启动使用的配置文件

    接着运行其客户端

    # 运行客户端
    redis-cli -p 6379
    
    • 因为本身就是本机,所以只需要指定端口就行了,不需要指定ip

    可以简单测试一下,例如 set get 一下,能拿到值就代表成功了

    H:关闭服务以及检查进程是否存在

    先看一下运行中时,进程的存在情况

    # 查看redis 进程
    ps -ef|grep redis
    

    在客户端中,可以通过 shutdown 和 exit 执行关闭(这个是在Redis客户端中执行)

    # 关闭
    127.0.0.1:6379> shutdown
    not connected> exit
    
    # 再次查看一下进程状况
    [root@centos7 bin]# ps -ef|grep redis
    

    (2) windows 不推荐

    我们可以去github中寻找windows版本,不过版本会有所滞后,官方起码是没有支持更新的,可能微软还想着能拽他一把。最新的版本好像也都是好几年前的了

    https://github.com/microsoftarchive/redis/releases

    解压即可用:分别启动 redis-server.exe 和 redis-cli.exe 就能直接测试使用了吗,有问题修改redis.windows.conf 配置文件

    • redis-server.exe:redis服务器端
    • redis-cli.exe:redis的客户端
    • redis.windows.conf:配置文件

    三 Redis 通用命令

    (一) 开闭命令

    (1) 启动 Redis 服务

    redis-server [--port 6379]
    

    有时候参数会过多,建议使用配置文件启动

    redis-server [xx/redis.conf]
    

    例如:redis-server myconfig/redis.conf

    (2) 客户端连接 Redis

    redis-cli [-h 127.0.0.1 -p 6379]
    

    例如 :redis-cli -p 6379

    (3) 停止 Redis

    在客户端中(标志有 127.0.0.1:6379>)直接输入 shutown 等即可

    # 关闭
    127.0.0.1:6379> shutdown
    not connected> exit
    

    若在目录中(前面为 $ 等),可以执行

    redis-cli shutdown
    kill redis-pid
    

    (4) 测试连通性

    返回 PONG 即连通了

    127.0.0.1:6379> ping
    PONG
    

    (二) key 以及通用操作

    注:每一种类型的存储方式是不太一样的,所以这里的操作不会讲到添加存储,下面会在每种类型中详细讲解。

    只是想简单先测试,可以先暂时用这几个命令(这是 String 类型的)

    • 可以使用 set key value 添加

      • set 为命令,key 为键,value 为值

      • 例如:set test ideal-20

    • get key 获取到值

    (1) 获取所有键

    • 语法:keys pattern
    127.0.0.1:6379> keys *
    1) "test"
    2) "test2"
    
    • * 作为通配符,表示任意字符,因为其会遍历所有键,然后显示所有键列表,时间复杂度O(n),数据量过大的环境,谨慎使用

    (2) 获取键总数

    • 语法:dbsize
    127.0.0.1:6379> dbsize
    (integer) 2
    
    • 内部变量存储此值,执行获取操作时,非遍历,因此时间复杂度O(1)

    (3) 判断当前 key 是否存在

    • 语法:exists key [key ...]
    127.0.0.1:6379> exists test
    (integer) 1
    
    • 最后返回的是存在的个数

    (4) 查询键类型

    • 语法: type key
    127.0.0.1:6379> type test
    string
    

    (5) 移动键

    • 语法:move key db
    127.0.0.1:6379> move test2 3
    (string) 1
    127.0.0.1:6379> select 3
    OK
    127.0.0.1:6379[3]> keys *
    1) "ideal-20-2"
    
    • 注:Redis 默认有 16 个数据库 move 代表移动到其中哪个去,然后 select 代表切换到这个数据库

    (6) 删除键

    • 语法:del key [key ...]
    127.0.0.1:6379> del test2
    (integer) 1
    

    (7) 设置过期时间

    • 秒语法:expire key seconds
    • 毫秒语法:pexpire key milliseconds
    127.0.0.1:6379> expire test 120
    (integer) 1
    

    (8) 查询key的生命周期(秒)

    • 秒语法:ttl key
    • 毫秒语法:pttl key
    127.0.0.1:6379> ttl test
    (integer) 116
    

    (9) 设置永不过期

    • 语法:persist key
    127.0.0.1:6379> persist test
    (integer) 1
    127.0.0.1:6379> ttl test
    (integer) -1
    

    (10) 更改键的名称

    • 语法:rename key newkey
    127.0.0.1:6379> rename test ideal
    OK
    127.0.0.1:6379> keys *
    1) "ideal"
    

    (11) 清除当前数据库

    • 语法:flushdb
    127.0.0.1:6379> flushdb
    OK
    127.0.0.1:6379> keys *
    (empty array)
    

    (12) 清除全部数据库的内容

    • 语法:flushall
    127.0.0.1:6379> flushall
    OK
    127.0.0.1:6379> keys *
    (empty array)
    127.0.0.1:6379> 
    

    四 常见支持类型操作

    (一) 字符串类型 - string

    (1) 存储

    • 语法:set key value [EX seconds] [PX milliseconds] [NX|XX]
      • 后面还可以选择性的跟随过期时间
    127.0.0.1:6379> set address beijing 5000
    OK
    

    (2) 获取

    • 语法:get key
    127.0.0.1:6379> get address
    “beijing”
    

    (3) 删除

    • 语法:del key
    127.0.0.1:6379> del address
    (string) 1
    

    (4) 递增或递减

    如果字符串中的值为数字类型,可以进行递增递减,其它类型会报错

    • 递增语法:incr key
    • 递增语法(指定步长):incrby key step
    • 递减语法:decr key
    • 递减语法(指定步长):decrby key step
    127.0.0.1:6379> set age 21 
    OK
    127.0.0.1:6379> incr age # 递增
    (integer) 22 
    127.0.0.1:6379> incrby age 5 # 递增 5
    (integer) 27
    127.0.0.1:6379> decr age # 递减
    (integer) 26
    127.0.0.1:6379> decrby age 5 # 递减 5
    (integer) 21
    

    (5) 追加内容

    • 语法:append key value
    127.0.0.1:6379> set ideal hello
    OK
    127.0.0.1:6379> append ideal ,ideal-20 # 追加内容
    (integer) 14
    127.0.0.1:6379> get ideal
    "hello,ideal-20"
    

    (6) 截取部分字符串

    • 语法:getrange key start end
    127.0.0.1:6379> get ideal
    "hello,ideal-20"
    127.0.0.1:6379> getrange ideal 0 3
    "hell"
    127.0.0.1:6379> getrange ideal 0 -1
    "hello,ideal-20"
    

    (7) 替换部分字符串

    • 语法:setrange key start
    127.0.0.1:6379> get ideal
    "hello,ideal-20"
    127.0.0.1:6379> setrange ideal 6 bwh # 从下标为6的位置开始替换
    (integer) 14
    127.0.0.1:6379> get ideal
    "hello,bwhal-20"
    

    (8) 获取值的长度

    • 语法:strlen key
    127.0.0.1:6379> strlen addr1
    (integer) 7
    

    (9) 不存在的时候才设置

    • 语法:setnx key value
      • 不存在,则创建
      • 存在,则失败
    127.0.0.1:6379> setnx address guangdong # address键 不存在,则创建
    (integer) 1
    127.0.0.1:6379> get address
    "guangdong"
    127.0.0.1:6379> setnx address beijing # address键 存在,则失败
    (integer) 0
    127.0.0.1:6379> get address
    "guangdong"
    

    (10) 同时存储获取多个值

    • 同时存储多个值:mset key1 value1 key2 value2 ...
    • 同时获取多个值:mget key1 key2
    • 同时存储多个值(保证不存在):msetnx key1 value1 key2 value2 ...
      • 此操作为原子性操作,要失败全部失败
    127.0.0.1:6379> mset addr1 beijing addr2 guangdong addr3 shanghai # 同时存储多个值
    OK
    127.0.0.1:6379> keys *
    1) "addr3"
    2) "addr2"
    3) "addr1"
    
    127.0.0.1:6379> mget addr1 addr2 addr3 # 同时获取多个值
    1) "beijing"
    2) "guangdong"
    3) "shanghai"
    
    127.0.0.1:6379> msetnx age1 20 age2 25 age3 30 # 第一次同时存储多个值(保证不存在)
    (integer) 1
    127.0.0.1:6379> msetnx age4 35 age5 40 age1 45 # 第二次同时存储多个值(保证不存在),失败了
    (integer) 0
    127.0.0.1:6379> 
    

    (11) 设置对象

    • 语法:key value (key 例如:user:1 ,value为一个json字符串)
    127.0.0.1:6379> set user:1 {name:zhangsan,age:20} # 存一个对象
    OK
    127.0.0.1:6379> keys *
    1) "user:1"
    127.0.0.1:6379> get user:1
    "{name:zhangsan,age:20}"
    
    • 以上这种 user:1 的设计在 Redis 中是允许的,例子如下
    • 语法:对象名:{id}:{filed}
    127.0.0.1:6379> mset user:1:name lisi user:1:age 25
    OK
    127.0.0.1:6379> mget user:1:name user:1:age
    1) "lisi"
    2) "25"
    
    

    (12) 先 get 后 set

    • 语法:getset
      • 先取到原来的值,然后再把新值覆盖,如果原先没有值返回 nil
    127.0.0.1:6379> getset addr beijing # 原先没有值,返回 nil
    (nil)
    127.0.0.1:6379> get addr
    "beijing"
    127.0.0.1:6379> getset addr guangdong # 原先有值,返回原先的值,然后覆盖新值
    "beijing"
    127.0.0.1:6379> get addr
    "guangdong"
    

    (二) 列表类型 - list

    (1) 添加

    A:从左或从右添加元素

    • lpush key value:将元素添加到列表左边
    • Rpush key value:将元素添加到列表右边

    下面演示添加到左边的,右边的是一样的就不演示了

    127.0.0.1:6379> lpush list1 A
    (integer) 1
    127.0.0.1:6379> lpush list1 B
    (integer) 2
    127.0.0.1:6379> lpush list1 C
    (integer) 3
    127.0.0.1:6379> lrange list1 0 -1
    1) "C"
    2) "B"
    3) "A"
    

    B:插入新值到某个值前后

    • 语法:linsert list before/after value newvalue
    127.0.0.1:6379> lrange list1 0 -1
    1) "A"
    2) "B"
    3) "C"
    
    127.0.0.1:6379> linsert list1 before C XXX # 在 C 前插入 XXX
    (integer) 4
    
    127.0.0.1:6379> lrange list1 0 -1
    1) "A"
    2) "B"
    3) "XXX"
    4) "C"
    

    (2) 获取:

    A:根据区间获取值

    • 语法:lrange key start end
    127.0.0.1:6379> lrange list1 0 -1 # 获取所有值
    1) "C"
    2) "B"
    3) "A"
     
    127.0.0.1:6379> lrange list1 0 1 # 获取指定区间的值
    1) "C"
    2) "B"
    

    B:根据下标获取值

    • 语法:lindex list 下标
    127.0.0.1:6379> lrange list1 0 -1
    1) "C"
    2) "B
    127.0.0.1:6379> lindex list1 0
    "C"
    127.0.0.1:6379> lindex list1 1
    "B"
    

    C:获取列表的长度

    • 语法 llen list
    127.0.0.1:6379> llen list1
    (integer) 1
    

    (3) 删除

    A:移除最左或最右的元素

    • lpop key:删除列表最左边的元素,且返回元素
    • rpop key:删除列表最右边的元素,且返回元素
    127.0.0.1:6379> lrange list1 0 -1
    1) "D"
    2) "C"
    3) "B"
    4) "A"
    
    127.0.0.1:6379> lpop list1 # 删除列表最左边的元素,且返回元素
    "D"
    127.0.0.1:6379> rpop list1 # 删除列表最右边的元素,且返回元素
    "A"
    
    127.0.0.1:6379> lrange list1 0 -1
    1) "C"
    2) "B"
    

    B:移除指定的值

    • 语法:lrem list num value
    127.0.0.1:6379> lrange list1 0 -1
    1) "C"
    2) "C"
    3) "B"
    4) "A"
    
    127.0.0.1:6379> lrem list1 1 A # 删除1个A
    (integer) 1
    127.0.0.1:6379> lrange list1 0 -1
    1) "C"
    2) "C"
    3) "B"
    
    127.0.0.1:6379> lrem list1 2 C # 删除2个C
    (integer) 2
    127.0.0.1:6379> lrange list1 0 -1
    1) "B"
    127.0.0.1:6379> 
    

    C:移除最后一个元素且添加到另一个list

    • rpoplpush list1 list2
    127.0.0.1:6379> lrange list1 0 -1
    1) "A"
    2) "B"
    3) "C"
    
    127.0.0.1:6379> rpoplpush list1 list2 # 移除 list1 中最后一个元素,且添加到list2 中去
    "C"
    
    127.0.0.1:6379> lrange list1 0 -1
    1) "A"
    2) "B"
    127.0.0.1:6379> lrange list2 0 -1
    1) "C"
    

    (4) 根据下标范围截取 list

    • 语法:ltrim list start end
    127.0.0.1:6379> rpush list1 A
    (integer) 1
    127.0.0.1:6379> rpush list1 B
    (integer) 2
    127.0.0.1:6379> rpush list1 C
    (integer) 3
    127.0.0.1:6379> rpush list1 D
    (integer) 4
    
    127.0.0.1:6379> ltrim list1 1 2 # 截取下标为1到2的值
    OK
    
    127.0.0.1:6379> lrange list1 0 -1
    1) "B"
    2) "C"
    

    (5) 替换指定下标的值

    语法:lset list 下标 value

    127.0.0.1:6379> exists list1 # 判断是否存在此list
    (integer) 0
    127.0.0.1:6379> lset list1 0 beijing # 不存在,替换报错
    (error) ERR no such key
    
    127.0.0.1:6379> lpush list1 guangdong # 创建一个list
    (integer) 1
    127.0.0.1:6379> lindex list1 0
    "guangdong"
    
    127.0.0.1:6379> lset list1 0 beijing # 存在,替换成功
    OK
    127.0.0.1:6379> lindex list1 0
    "beijing"
    

    (三) 集合类型 - set

    set:一种无序(不保证有序)集合,且元素不能重复

    (1) 添加

    • 语法:sadd key value
    127.0.0.1:6379> sadd set1 A
    (integer) 1
    127.0.0.1:6379> sadd set1 B
    (integer) 1
    127.0.0.1:6379> sadd set1 C
    (integer) 1
    127.0.0.1:6379> sadd set1 C # set的值不能重复
    (integer) 0
    127.0.0.1:6379> smembers set1 # 查询指定set的所有值,乱序
    1) "B"
    2) "A"
    3) "C"
    

    (2) 获取

    A:获取set集合中的所有元素

    • 语法:smembers key
    127.0.0.1:6379> smesmbers set1 # 查询指定set的所有值,乱序
    1) "B"
    2) "A"
    3) "C"
    

    B:获取元素的个数

    • 语法:scard set
    127.0.0.1:6379> scard set1
    (integer) 3
    

    C:随机获取元素

    • 语法:sembers set [num]
      • 默认获取一个随机元素,后跟数字,代表随机获取几个元素
    127.0.0.1:6379> smembers set1
    1) "D"
    2) "B"
    3) "A"
    4) "C"
    
    127.0.0.1:6379> srandmember set1 # 获取一个随机元素
    "D"
    127.0.0.1:6379> srandmember set1 # 获取一个随机元素
    "B"
    
    127.0.0.1:6379> srandmember set1 2 # 获取两个随机元素
    1) "A"
    2) "D"
    

    (3) 删除

    A:删除set集合中某元素

    • 语法:srem key value
    127.0.0.1:6379> srem set1 C # 删除 C 这个元素
    (integer) 1
    
    127.0.0.1:6379> smembers set1
    1) "B"
    2) "A"
    

    B:随机删除一个元素

    • 语法:spop set
    127.0.0.1:6379> smembers set1
    1) "D"
    2) "B"
    3) "A"
    4) "C"
    127.0.0.1:6379> spop set1 # 随机删除一个元素
    "A"
    127.0.0.1:6379> spop set1 # 随机删除一个元素
    "B"
    127.0.0.1:6379> smembers set1
    1) "D"
    2) "C"
    

    (4) 移动指定值到另一个set

    • 语法:smove set1 set2 value
    127.0.0.1:6379> smembers set1
    1) "D"
    2) "C"
    
    127.0.0.1:6379> smove set1 set2 D # 从 set1 移动 D 到 set2
    (integer) 1
    
    127.0.0.1:6379> smembers set1
    1) "C" 
    127.0.0.1:6379> smembers set2
    1) "D"
    

    (5) 交集 并集 差集

    • sinter set1 set2:交集
    • sunion set1 set2:并集
    • sdiff set1 set2:差集
    127.0.0.1:6379> sadd set1 A
    (integer) 1
    127.0.0.1:6379> sadd set1 B
    (integer) 1
    127.0.0.1:6379> sadd set1 C
    (integer) 1
    
    127.0.0.1:6379> sadd set2 B
    (integer) 1
    127.0.0.1:6379> sadd set2 C
    (integer) 1
    127.0.0.1:6379> sadd set2 D
    (integer) 1
    127.0.0.1:6379> sadd set2 E
    (integer) 1
    
    127.0.0.1:6379> sinter set1 set2 # 交集
    1) "B"
    2) "C"
    127.0.0.1:6379> sunion set1 set2 # 并集
    1) "D"
    2) "E"
    3) "C"
    4) "B"
    5) "A"
    127.0.0.1:6379> sdiff set1 set2 # 差集
    1) "A"
    

    (四) 有序集合类型 - sortedset/zset

    此类型和 set 一样也是 string 类型元素的集合,且不允许重复的元素

    不同的是每个元素都会关联一个double类型的分数,redis正是通过分数来为集合中的成员进行从小到大的排序

    有序集合的成员是唯一,但分数(score)却可以重复

    (1) 添加

    • 语法:zadd key score value [score value ... ...]
    127.0.0.1:6379> zadd sortedset1 20 zhangsan # 添加一个
    (integer) 1
    127.0.0.1:6379> zadd sortedset1 10 lisi 60 wangwu # 添加多个
    (integer) 2
    

    (2) 获取

    A:获取所有值(默认排序)

    • 语法:zrange sortedset start end [withscores]
      • 根据那个值的大小进行了排序,例如上面的 10 20 60
    127.0.0.1:6379> zrange sortedset1 0 -1
    1) "lisi"
    2) "zhangsan"
    3) "wangwu"
    

    B:获取所有值(从小到大和从大到小)

    • zrangebyscore sortedset -inf +inf:从小到大
    • zrevrange sortedset 0 -1:从大到小
    127.0.0.1:6379> zrangebyscore sortedset1 -inf +inf # 从小到大
    1) "lisi"
    2) "zhangsan"
    3) "wangwu"
    
    127.0.0.1:6379> zrevrange sortedset1 0 -1 # 从大到小
    1) "wangwu"
    2) "zhangsan"
    3) "lisi"
    

    C:获取值且附带数值

    • zrangebyscore sortedset -inf +inf withscores:从小到大且附带值
    127.0.0.1:6379> zrangebyscore sortedset1 -inf +inf withscores # 显示从小到大且附带值
    1) "lisi"
    2) "10"
    3) "zhangsan"
    4) "20"
    5) "wangwu"
    6) "60"
    
    127.0.0.1:6379> zrangebyscore sortedset1 -inf 20 withscores # 显示从小到大,且数值小于20的
    1) "lisi"
    2) "10"
    3) "zhangsan"
    4) "20"
    127.0.0.1:6379> 
    

    D:获取有序集合中的个数

    • 语法:zcard sortedset
    127.0.0.1:6379> zcard sortedset1
    (integer) 2
    

    E:获取指定区间成员数量

    • 语法:zcount sortedset start end (strat 和 end是指那个数值,而不是什么下标)
    127.0.0.1:6379> zcount sortedset1 10 60
    (integer) 3
    

    (2) 删除

    • zrem key value
    127.0.0.1:6379> zrange sortedset1 0 -1
    1) "lisi"
    2) "zhangsan"
    3) "wangwu"
    
    127.0.0.1:6379> zrem sortedset1 wangwu # 删除 wangwu 这个元素
    (integer) 1
    
    127.0.0.1:6379> zrange sortedset1 0 -1
    1) "lisi"
    2) "zhangsan"
    

    (五) 哈希类型 - hash

    (1) 添加

    A:普通添加

    • 语法:hset hash field value
    127.0.0.1:6379> hset hash1 username admin
    (integer) 1
    127.0.0.1:6379> hset hash1 password admin
    (integer) 1
    

    B:不存在才可以添加

    • 语法:hsetnx hash filed value
    127.0.0.1:6379> hsetnx hash1 username admin888 # 已存在,失败
    (integer) 0
    
    127.0.0.1:6379> hsetnx hash1 code 666 # 不存在,成功
    (integer) 1
    

    (2) 获取

    A:获取指定的field对应的值

    • 语法:hget hash field [ key field ... ...]
    127.0.0.1:6379> hget hash1 password
    "admin"
    

    B:获取所有的field和value

    • 语法:hgetall hash
    127.0.0.1:6379> hgetall hash1
    1) "username"
    2) "admin"
    3) "password"
    4) "admin"
    

    C:获取 hash 的字段数量

    • 语法:hlen hash
    127.0.0.1:6379> hlen hash1
    (integer) 2
    

    D:只获取所有 field 或 value

    • hkeys hash:获取所有 field 字段
    • hvals hash:获取所有 value 值
    127.0.0.1:6379> hkeys hash1 # 获取所有 field 字段
    1) "username"
    2) "password"
    
    127.0.0.1:6379> hvals hash1 # 获取所有 value 值
    1) "admin"
    2) "admin"
    

    (3) 删除

    • 语法:hdel hash field
    127.0.0.1:6379> hdel hash1 username
    (integer) 1
    

    (4) 自增自减

    • hincrby hash field 增量
    127.0.0.1:6379> hsetnx hash1 code 666
    (integer) 1
    127.0.0.1:6379> hincrby hash1 code 2
    (integer) 668
    127.0.0.1:6379> hincrby hash1 code -68
    (integer) 600
    

    五 三种特殊数据类型

    (一) Geospatial(地理位置)

    使用经纬度,作为地理坐标,然后存储到一个有序集合 zset/sortedset 中去保存,所以 zset 中的命令也是可以使用的

    • 特别是需要删除一个位置时,没有GEODEL命令,是因为你可以用ZREM来删除一个元素(其结构就是一个有序结构)
    • Geospatial 这个类型可以用来实现存储城市坐标,一般都不是自己录入,因为城市数据都是固定的,所以都是通过 Java 直接导入的,下面都是一些例子而已
    • Geospatial 还可以用来实现附近的人这种概念,每一个位置就是人当前的经纬度,还有一些能够测量距离等等的方法,后面都会提到

    命令列表:

    (1) 存储经纬度

    • 语法:geoadd key longitud latitude member [..]

      • longitud——经度、 latitude——纬度

      • 有效的经度从-180度到180度。

      • 有效的纬度从-85.05112878度到85.05112878度。

    127.0.0.1:6379> geoadd china:city 116.413384 39.910925 beijing
    (integer) 1
    127.0.0.1:6379> geoadd china:city 113.271431 23.135336 guangzhou
    (integer) 1
    127.0.0.1:6379> geoadd china:city 113.582555 22.276565 zhuhai
    (integer) 1
    127.0.0.1:6379> geoadd china:city 112.556391 37.876989 taiyuan
    (integer) 1
    

    (2) 获取集合中一个或者多个成员的坐标

    • 语法:geopos key member [member..]
    127.0.0.1:6379> geopos china:city beijing zhuhai
    1) 1) "116.41338318586349487"
       2) "39.9109247398676743"
    2) 1) "116.41338318586349487"
       2) "39.9109247398676743"
    

    (3) 返回两个给定位置之间的距离

    • 语法:geodist key member1 member2 [unit]

      • 单位默认为米,可以修改,跟在 member 后即可,例如 km

      • 指定单位的参数 unit 必须是以下单位的其中一个:

        • m 表示单位为米

        • km 表示单位为千米

        • mi 表示单位为英里

    下一篇:没有了