mysql是一种关系型数据库(RDB、RMDBS)。

数据库类型

关系型数据库(RMDBS)

数据库中表与表的数据之间存在某种关联的内在关系,因为这种关系,所以我们称这种数据库为关系型数据库。

典型:Mysql/MariaDB、postgreSQL、Oracle、SQLServer、DB2、Access、SQLlite3

特点:

  1. 全部使用SQL(结构化查询语言)进行数据库操作。
  2. 都存在主外键关系,表,等等关系特征。
  3. 大部分都支持各种关系型的数据库的特性:存储过程、触发器、视图、临时表、模式、函数

非关系型数据库(NoSQL)

NOSQL:not only sql,泛指非关系型数据库。

泛指那些不使用SQL语句进行数据操作的数据库,所有数据库中只要不使用SQL语句的都是非关系型数据库。

典型:Redis、MongoDB、hbase、 Hadoop、elasticsearch、图数据库。。。。

特点:

  1. 每一款都不一样。用途不一致,功能不一致,各有各的操作方式。
  2. 基本不支持主外键关系,也没有事务的概念。(MongoDB号称最接近关系型数据库的,所以MongoDB有这些的。)

redis

Redis(Remote Dictionary Server ,远程字典服务) 是一个高性能的key-value数据格式的内存数据库,是NoSQL数据库。redis的出现主要是为了替代早起的Memcache缓存系统的。
内存型(数据存放在内存中)的非关系型(nosql)key-value(键值存储)数据库,
支持数据的持久化(基于RDB和AOF,注: 数据持久化时将数据存放到文件中,每次启动redis之后会先将文
件中数据加载到内存),经常用来做缓存、数据共享、购物车、消息队列、计数器、限流等。(最基本的就是缓存一些经常用到的数据,提高读写速度)。

redis的官方只提供了linux版本的redis,window系统的redis是微软团队根据官方的linux版本高仿的。

官方原版: https://redis.io/

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

3.1 redis下载和安装

下载地址: https://github.com/MicrosoftArchive/redis/releases

redis - 图1

redis - 图2

redis - 图3

redis - 图4

redis - 图5

redis - 图6

redis - 图7

redis - 图8

redis - 图9

使用以下命令启动redis服务端

  1. redis-server C:/tool/redis/redis.windows.conf

redis - 图10

关闭上面这个cmd窗口就关闭redis服务器服务了。

redis作为windows服务启动方式

  1. redis-server --service-install redis.windows.conf

启动服务:redis-server —service-start
停止服务:redis-server —service-stop

  1. # 如果连接操作redis,可以在终端下,使用以下命令:
  2. redis-cli

ubuntu下安装:

  1. 安装命令:sudo apt-get install -y redis-server
  2. 卸载命令:sudo apt-get purge --auto-remove redis-server
  3. 关闭命令:sudo service redis-server stop
  4. 开启命令:sudo service redis-server start
  5. 重启命令:sudo service redis-server restart
  6. 配置文件:/etc/redis/redis.conf

3.2 redis的配置

  1. sudo cat /etc/redis/redis.conf

redis 安装成功以后,window下的配置文件保存在软件 安装目录下,如果是mac或者linux,则默认安装/etc/redis/redis.conf

3.2.1 redis的核心配置选项

redis与mysql类似,也是C/S架构的软件,所以存在客户端和服务端,默认的redis的服务端时redis-server,默认提供的redis客户端是redis-cli。

绑定ip:如果需要远程访问,可将此注释,或绑定1个真实ip

  1. bind 127.0.0.1

端⼝,默认为6379

  1. port 6379

是否以守护进程运行 [windows下需要设置]

  • 如果以守护进程运行,则不会在命令阻塞,类似于服务
  • 如果以守护进程运行,则当前终端被阻塞
  • 设置为yes表示守护进程,设置为no表示⾮守护进程
  • 推荐设置为yes
  1. daemonize yes

RDB持久化的备份文件

  1. dbfilename dump.rdb

RDB持久化数据库数据文件的所在目录

  1. dir /var/lib/redis

日志等级和日期文件的所在目录

  1. loglevel notice
  2. logfile /var/log/redis/redis-server.log

进程ID文件

  1. pidfile /var/run/redis/redis-server.pid

数据库,默认有16个,数据名是不能自定义的,只能是0-15之间,当然这个15是数据库数量-1

  1. database 16

redis的登录密码,生产阶段打开,开发阶段避免麻烦,一般都是注释的。

  1. # requirepass foobared

注意:开启了以后,redis-cli终端下使用 auth 密码来认证登录。

redis - 图11

RDB持久化的备份频率,文件格式是二进制

  1. save 900 1
  2. save 300 10
  3. save 60 10000

RDB持久化备份文件的文件名和路径

  1. dbfilename dump.rdb
  2. dir /var/lib/redis

AOF持久化的开启配置项,默认是no关闭的。备份的文件格式:文本格式

  1. appendonly no

AOF持久化的备份文件,存储路径与RDB备份文件路径是一致的。

  1. appendfilename "appendonly.aof"

AOF持久化备份的频率[时间]

  1. # appendfsync always # 每次修改键对应数据时都会触发一次aof
  2. appendfsync everysec # 每秒备份,工作中最常用。
  3. # appendfsync no

一主二从三哨兵

1.主从简介

1.主从用法

像MySQL一样,redis是支持主从同步的,而且也支持一主多从以及多级从结构。 主从结构,一是为了纯粹的冗余备份,二是为了提升读性能,比如很消耗性能的SORT就可以由从服务器来承担。 redis的主从同步是异步进行的,这意味着主从同步不会影响主逻辑,也不会降低redis的处理性能。 主从架构中,可以考虑关闭主服务器的数据持久化功能,只让从服务器进行持久化,这样可以提高主服务器的处理性能。

2.主从同步原理

主从 – 同步原理 从服务器会向主服务器发出SYNC指令,当主服务器接到此命令后, 就会调用BGSAVE指令来创建一个子进程专门进行数据持久化工作, 也就是将主服务器的数据写入RDB文件中。在数据持久化期间,主 服务器将执行的写指令都缓存在内存中。 在BGSAVE指令执行完成后,主服务器会将持久化好的RDB文件发 送给从服务器,从服务器接到此文件后会将其存储到磁盘上,然后 再将其读取到内存中。这个动作完成后,主服务器会将这段时间缓 存的写指令再以redis协议的格式发送给从服务器。 另外,要说的一点是,即使有多个从服务器同时发来SYNC指令, 主服务器也只会执行一次BGSAVE,然后把持久化好的RDB文件发 给多个从服务器。 而在2.8版本之后,redis支持了效率更高的增量同步策略,这大大降 低了连接断开的恢复成本。主服务器会在内存中维护一个缓冲区, 缓冲区中存储着将要发给从服务器的内容。从服务器在与主服务器 出现网络瞬断之后,从服务器会尝试再次与主服务器连接,一旦连 接成功,主服务器就会向从服务器发送增量内容。 增量同步功能,需要服务器端支持全新的PSYNC指令。这个指令, 只有在redis-2.8之后才具有。

2.部署主从同步

1.准备三台机器

master 192.168.13.139 slave1 192.168.13.140 slave2 192.168.13.133 三台机器都要做: systemctl stop firewalld && setenforce 0 #三台机器全部关闭防火墙和selinux yum -y install gcc make #下载编译安装工具 wget http://download.redis.io/releases/redis-4.0.9.tar.gz #下载redis

2.master配置

[root@master ~]# mkdir -p /data/yjssjm #创建工作目录(自定义的) [root@master ~]# tar xzf redis-4.0.9.tar.gz -C /data/yjssjm/ #解压,如果你的包跟我的不一样请不要直接复制 [root@master ~]# cd /data/yjssjm/ [root@master yjssjm]# mv redis-4.0.9/ redis #改名字 [root@master yjssjm]# cd redis/ [root@master redis]# make 注:如果报错请将刚才解压的安装包删除掉,再次重新解压并进行make安装即可。 [root@redis-master redis]# vim redis.conf #找到并修改 bind 0.0.0.0 protected-mode no # 将加密保护关掉。此时外部网络可以直接访问

redis - 图12

[root@master src]# cd src [root@master src]# ./redis-server ../redis.conf & #启动redis服务,并且加载此文件中的配置信息

如果你嫌上面的启动方式太不容易记,可以进行以下操作来配置到系统管理工具里面

[root@master redis]# cp redis.conf redis.conf.bak [root@master redis]# vim redis.conf 添加以下代码 [Unit] Description=Redis After=network.target [Service] ExecStart=/data/yjssjm/redis/src/redis-server /data/yjssjm/redis/redis.conf --daemonize no ExecStop=/data/yjssjm/redis/src/redis-cli -h 127.0.0.1 -p 6379 shutdown [Install] WantedBy=multi-user.target ====================================================================================== 参数详解: • [Unit] 表示这是基础信息 • Description 是描述 • After 是在那个服务后面启动,一般是网络服务启动后启动 • [Service] 表示这里是服务信息 • ExecStart 是启动服务的命令 • ExecStop 是停止服务的指令 • [Install] 表示这是是安装相关信息 • WantedBy 是以哪种方式启动:multi-user.target表明当系统以多用户方式(默认的运行级别)启动时,这个服务需要被自动运行。 ========================================================================================= 然后你就可以用以下方式开启服务了 [root@master system]# systemctl daemon-reload #重新加载配置文件 [root@master system]# systemctl start redis.service

3.slave1配置

[root@slave1 ~]# mkdir -p /data/yjssjm #创建工作目录(自定义的) [root@slave1 ~]# tar xzf redis-4.0.9.tar.gz -C /data/yjssjm/ #解压,如果你的包跟我的不一样请不要直接复制 [root@slave1 ~]# cd /data/yjssjm/ [root@slave1 yjssjm]# mv redis-4.0.9/ redis #改名字 [root@slave1 yjssjm]# cd redis/ [root@slave1 redis]# make 注:如果报错请将刚才解压的安装包删除掉,再次重新解压并进行make安装即可。 [root@slave1 redis]# vim redis.conf #找到并修改 bind 0.0.0.0 protected-mode no # 将加密保护关掉。此时外部网络可以直接访问 slaveof 192.168.13.139 6379 #master的内网ip和端口

redis - 图13

redis - 图14

[root@slave1 src]# cd src [root@slave1 src]# ./redis-server ../redis.conf & #启动redis服务,并且加载此文件中的配置信息

4.slave2配置

[root@slave2 ~]# mkdir -p /data/yjssjm #创建工作目录(自定义的) [root@slave2 ~]# tar xzf redis-4.0.9.tar.gz -C /data/yjssjm/ #解压,如果你的包跟我的不一样请不要直接复制 [root@slave2 ~]# cd /data/yjssjm/ [root@slave2 yjssjm]# mv redis-4.0.9/ redis #改名字 [root@slave2 yjssjm]# cd redis/ [root@slave2 redis]# make 注:如果报错请将刚才解压的安装包删除掉,再次重新解压并进行make安装即可。 [root@slave2 redis]# vim redis.conf #找到并修改 bind 0.0.0.0 protected-mode no # 将加密保护关掉。此时外部网络可以直接访问 slaveof 192.168.13.139 6379 #master的内网ip和端口

redis - 图15

redis - 图16

[root@slave2 src]# cd src [root@slave2 src]# ./redis-server ../redis.conf & #启动redis服务,并且加载此文件中的配置信息

5.测试

1.在master上面执行 [root@master src]# ./redis-cli 127.0.0.1:6379> ping PONG 127.0.0.1:6379> set name yjssjm OK 127.0.0.1:6379> get name "yjssjm" 2.分别在slave1和slave2上面执行: [root@slave1 src]# ./redis-cli 127.0.0.1:6379> ping PONG 127.0.0.1:6379> get name "yjssjm"

redis - 图17

3.redis-sentinel—-哨兵模式

1.介绍

1、哨兵简介:Redis Sentinel Sentinel(哨兵)是用于监控redis集群中Master状态的工具,其已经被集成在redis2.4+的版本中是Redis官方推荐的高可用性(HA)解决方案。 2、作用 1):Master状态检测 2):如果Master异常,则会进行Master-Slave切换,将其中一个Slave作为Master,将之前的Master作为Slave 3):Master-Slave切换后,sentinel.conf的监控目标会随之调换 3、工作模式 1):每个Sentinel以每秒钟一次的频率向它所知的Master,Slave以及其他 Sentinel 实例发送一个 PING 命令 2):如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被 Sentinel 标记为主观下线。 3):如果一个Master被标记为主观下线,则正在监视这个Master的所有 Sentinel 要以每秒一次的频率确认Master的确进入了主观下线状态。 4):当有足够数量的 Sentinel(大于等于配置文件指定的值)在指定的时间范围内确认Master的确进入了主观下线状态, 则Master会被标记为客观下线 。 4、主观下线和客观下线 主观下线:Subjectively Down,简称 SDOWN,指的是当前 一个Sentinel 实例对某个redis服务器做出的下线判断。 客观下线:Objectively Down, 简称 ODOWN,指的是多个 Sentinel 实例在对Master Server做出 SDOWN 判断,并且通过 SENTINEL is-master-down-by-addr 命令互相交流之后,得出的Master Server下线判断,然后开启failover

2.配置

三台机器都需要进行以下操作

1.每台机器上修改sentinel.conf配置文件:修改如下配置 [root@master src]# cd .. [root@master redis]# vim sentinel.conf sentinel monitor mymaster 192.168.13.139 6379 2 #当集群中有2个sentinel认为master死了时,才能真正认为该master已经不可用了。mymaster时自定义的集群名字 (slave上面写的是master的ip,master写自己ip) sentinel down-after-milliseconds mymaster 3000 #单位毫秒 3000毫秒没响应,认为主观下线 sentinel failover-timeout mymaster 10000 #若sentinel在该配置值内未能完成failover(故障转移)操作(即故障时master/slave自动切换),则认为本次failover失败。 protected-mode no #关闭加密模式--新添加到sentinel配置文件中 2.每台机器启动哨兵服务: [root@redis-master redis]# ./src/redis-sentinel sentinel.conf 注意:在生产环境下将哨兵模式启动放到后台执行: ./src/redis-sentinel sentinel.conf &

redis - 图18

redis - 图19

将master的哨兵模式退出(Crtl+c),再将redis服务stop了,在两台slave上面查看其中一台是否切换为master:(没有优先级,为随机切换) [root@master redis]# systemctl stop redis.service 或者用kill命令杀死 注意:kill命令一定要杀的是服务

redis - 图20

3.2.2 Redis的使用

redis是一款基于CS架构的数据库,所以redis有客户端redis-cli,也有服务端redis-server。

其中,客户端可以使用python等编程语言,也可以终端下使用命令行工具管理redis数据库,甚至可以安装一些别人开发的界面工具,例如:RDM。

redis - 图21

redis-cli客户端连接服务器:

  1. # redis-cli -h `redis服务器ip` -p `redis服务器port`
  2. redis-cli -h 10.16.244.3 -p 6379

3.3 redis数据类型

  1. redis就是一个全局的大字典,key就是数据的唯一标识符。根据key对应的值不同,可以划分成5个基本数据类型。
  2. 1. string类型:
  3. 字符串类型,是 Redis 中最为基础的数据存储类型,它在 Redis 中是二进制安全的,也就是byte类型。
  4. 单个数据的最大容量是512M
  5. key: b"值"
  6. 2. hash类型:
  7. 哈希类型,用于存储对象/字典,对象/字典的结构为键值对。key、域、值的类型都为string。域在同一个hash中是唯一的。
  8. key:{
  9. 域(属性): 值,
  10. 域:值,
  11. 域:值,
  12. 域:值,
  13. ...
  14. }
  15. 3. list类型:
  16. 列表类型,它的子成员类型为string
  17. key: [ 1,值2, 3..... ]
  18. 4. set类型:
  19. 无序集合,它的子成员类型为string类型,元素唯一不重复,没有修改操作。
  20. key: {值1, 4, 3, ...., 5}
  21. 5. zset类型(sortedSet):
  22. 有序集合,它的子成员值的类型为string类型,元素唯一不重复,没有修改操作。权重值1从小到大排列。
  23. key: {
  24. 1 权重值1(数字);
  25. 2 权重值2;
  26. 3 权重值3;
  27. 4 权重值4;
  28. }

redis中的所有数据操作,如果设置的键不存在则为添加,如果设置的键已经存在则修改

3.4 string

设置键值

set 设置的数据没有额外操作时,是不会过期的。

  1. set key value

设置键为name值为xiaoming的数据

  1. set name xiaoming

redis - 图22

设置一个键,当键不存在时才能设置成功,用于一个变量只能被设置一次的情况。

  1. setnx key value

一般用于给数据加锁

  1. 127.0.0.1:6379> setnx goods_1 101
  2. (integer) 1
  3. 127.0.0.1:6379> setnx goods_1 102
  4. (integer) 0 # 表示设置不成功
  5. 127.0.0.1:6379> del goods_1
  6. (integer) 1
  7. 127.0.0.1:6379> setnx goods_1 102
  8. (integer) 1

设置键值的过期时间

redis中可以对一切的数据进行设置有效期。

以秒为单位

  1. setex key seconds value

设置键为name值为xiaoming过期时间为20秒的数据

  1. setex name 20 xiaoming

实用set设置的数据会永久存储在redis中,如果实用setex对同名的key进行设置,可以把永久有效的数据设置为有时间的临时数据。

设置多个键值

  1. mset key1 value1 key2 value2 ...

例3:设置键为a1值为python、键为a2值为java、键为a3值为c

  1. mset a1 python a2 java a3 c

字符串拼接值

  1. append key value

向键为a1中拼接值haha

  1. append title "我的"
  2. append title "redis"
  3. append title "学习之路"

根据键获取值

根据键获取值,如果不存在此键则返回nil,相当于python的None

  1. get key

获取键name的值

  1. get name

根据多个键获取多个值

  1. mget key1 key2 ...

获取键a1、a2、a3的值

  1. mget a1 a2 a3

自增自减

  1. set id 1
  2. incr id # 相当于id+1
  3. get id # 2
  4. incr id # 相当于id+1
  5. get id # 3
  6. set goods_id_1 10
  7. decr goods_id_1 # 相当于 id-1
  8. get goods_id_1 # 8
  9. decr goods_id_1 # 相当于id-1
  10. get goods_id_1 # 8

获取字符串的长度

  1. set name xiaoming
  2. strlen name # 8

比特流操作

签到记录

8位就是1byte ==> 0010 0100

  1. BITCOUNT # 统计字符串被设置为1的bit数.
  2. BITPOS # 返回字符串里面第一个被设置为1或者0的bit位。
  3. SETBIT # 设置一个bit数据的值
  4. GETBIT # 获取一个bit数据的值
  1. SETBIT mykey 7 1
  2. # 00000001
  3. getbit mykey 7
  4. # 00000001
  5. SETBIT mykey 4 1
  6. # 00001001
  7. SETBIT mykey 15 1
  8. # 0000100100000001
  9. BITCOUNT mykey
  10. # 3
  11. BITPOS mykey 1
  12. # 4

3.5 key操作

redis中所有的数据都是通过key(键)来进行操作,这里我们学习一下关于任何数据类型都通用的命令。

查找键

参数支持简单的正则表达式

  1. keys pattern

查看所有键

  1. keys *

例子:

  1. # 查看名称中包含`a`的键
  2. keys *a*
  3. # 查看以a开头的键
  4. keys a*
  5. # 查看以a结尾的键
  6. keys *a
  7. # 数字结尾
  8. keys *[1-9]

判断键是否存在

如果存在返回1,不存在返回0

  1. exists key1

判断键title是否存在

  1. exists title

查看键的数据类型

  1. type key
  2. # string 字符串
  3. # hash 哈希类型
  4. # list 列表类型
  5. # set 无序集合
  6. # zset 有序集合

查看键的值类型

  1. type name
  2. # string
  3. sadd member_list xiaoming xiaohong xiaobai
  4. # (integer) 3
  5. type member_list
  6. # set
  7. hset user_1 name xiaobai age 17 sex 1
  8. # (integer) 3
  9. type user_1
  10. # hash
  11. lpush brothers zhangfei guangyu liubei xiaohei
  12. # (integer) 4
  13. type brothers
  14. # list
  15. zadd achievements 61 xiaoming 62 xiaohong 83 xiaobai 78 xiaohei 87 xiaohui 99 xiaolong
  16. # (integer) 6
  17. type achievements
  18. # zset

删除键以及键对应的值

  1. del key1 key2 ...

查看键的有效期

  1. ttl key
  2. # 结果结果是秒作为单位的整数
  3. # -1 表示永不过期
  4. # -2 表示当前数据已经过期,查看一个不存在的数据的有效期就是-2

设置key的有效期

给已有的数据重新设置有效期,redis中所有的数据都可以通过expire来设置它的有效期。有效期到了,数据就被删除。

  1. expire key seconds

清空所有key

慎用,一旦执行,则redis所有数据库0~15的全部key都会被清除

  1. flushall

key重命名

  1. rename oldkey newkey

把name重命名为username

  1. set name xioaming
  2. rename name username
  3. get username

select切换数据库

  1. redis的配置文件中,默认有0~15之间的16个数据库,默认操作的就是0号数据库
  2. select <数据库ID>

操作效果:

  1. # 默认处于0号库
  2. 127.0.0.1:6379> select 1
  3. OK
  4. # 这是在1号库
  5. 127.0.0.1:6379[1]> set name xiaoming
  6. OK
  7. 127.0.0.1:6379[1]> select 2
  8. OK
  9. # 这是在2号库
  10. 127.0.0.1:6379[2]> set name xiaohei
  11. OK

auth认证

  1. redis中,如果配置了requirepass登录密码,则进入redis-cli的操作数据之前,必须要进行登录认证。
  2. 注意:在redis6.0以后,redis新增了用户名和密码登录,可以选择使用,也可以选择不适用,默认关闭的。
  3. redis6.0以前,redis只可以在配置文件中,可以选择开启密码认证,也可以关闭密码认证,默认关闭的。
  4. redis-cli
  5. 127.0.0.1:6379> auth <密码>
  6. OK # 认证通过

3.6 hash

类似python的字典,但是成员只能是string,专门用于结构化的数据信息。

结构:

  1. key:{
  2. field:值value
  3. }

设置指定键的属性/域

设置指定键的单个属性,如果key不存在,则表示创建一个key对应的哈希数据,如果key存在,而field不存在,则表示当前哈希数据新增一个成员,如果field存在,则表示修改哈希对应的对应成员的值。

  1. hset key field value
  2. # redis5.0版本以后,hset可以一次性设置多个哈希的成员数据
  3. hset key field1 value1 field2 value2 field3 value3 ...

设置键 user_1的属性namexiaoming

  1. 127.0.0.1:6379> hset user_1 name xiaoming # user_1没有会自动创建
  2. (integer) 1
  3. 127.0.0.1:6379> hset user_1 name xiaohei # user_1中重复的属性会被修改
  4. (integer) 0
  5. 127.0.0.1:6379> hset user_1 age 16 # user_1中重复的属性会被新增
  6. (integer) 1
  7. 127.0.0.1:6379> hset user:1 name xiaohui # user:1会在redis界面操作中以:作为目录分隔符
  8. (integer) 1
  9. 127.0.0.1:6379> hset user:1 age 15
  10. (integer) 1
  11. 127.0.0.1:6379> hset user:2 name xiaohong age 16 # 一次性添加或修改多个属性

设置指定键的多个属性[hmset已经慢慢淘汰了,hset就可以实现多个属性]

  1. hmset key field1 value1 field2 value2 ...

设置键user_1的属性namexiaohong、属性age17,属性sex为1

  1. hmset user:3 name xiaohong age 17 sex 1

获取指定键的域/属性的值

获取指定键所有的域/属性

  1. hkeys key

获取键user的所有域/属性

  1. 127.0.0.1:6379> hkeys user:2
  2. 1) "name"
  3. 2) "age"
  4. 127.0.0.1:6379> hkeys user:3
  5. 1) "name"
  6. 2) "age"
  7. 3) "sex"

获取指定键的单个域/属性的值

  1. hget key field

获取键user:3属性name的值

  1. 127.0.0.1:6379> hget user:3 name
  2. "xiaohong"

获取指定键的多个域/属性的值

  1. hmget key field1 field2 ...

获取键user:2属性nameage的值

  1. 127.0.0.1:6379> hmget user:2 name age
  2. 1) "xiaohong"
  3. 2) "16"

获取指定键的所有值

  1. hvals key

获取指定键的所有域值对

  1. 127.0.0.1:6379> hvals user:3
  2. 1) "xiaohong"
  3. 2) "17"
  4. 3) "1"

删除指定键的域/属性

  1. hdel key field1 field2 ...

删除键user:3的属性sex/age/name,当键中的hash数据没有任何属性,则当前键会被redis删除

  1. hdel user:3 sex age name

判断指定属性/域是否存在于当前键对应的hash中

  1. hexists key field

判断user:2中是否存在age属性

  1. 127.0.0.1:6379> hexists user:3 age
  2. (integer) 0
  3. 127.0.0.1:6379> hexists user:2 age
  4. (integer) 1
  5. 127.0.0.1:6379>

属性值自增自减

  1. hincrby key field number

给user:2的age属性在原值基础上+/-10,然后在age现有值的基础上-2

  1. # 按指定数值自增
  2. 127.0.0.1:6379> hincrby user:2 age 10
  3. (integer) 77
  4. 127.0.0.1:6379> hincrby user:2 age 10
  5. (integer) 87
  6. # 按指定数值自减
  7. 127.0.0.1:6379> hincrby user:2 age -10
  8. (integer) 77
  9. 127.0.0.1:6379> hincrby user:2 age -10

3.7 list

类似python的lis列表数据类型,但是redis中的list的子成员类型为string。

添加子成员

  1. # 在左侧(前,上)添加一条或多条成员数据
  2. lpush key value1 value2 ...
  3. # 在右侧(后,下)添加一条或多条成员数据
  4. rpush key value1 value2 ...
  5. # 在指定元素的左边(前)/右边(后)插入一个或多个数据
  6. linsert key before 指定成员 value1 value2 ....
  7. linsert key after 指定成员 value1 value2 ....

从键为brother的列表左侧添加一个或多个数据liubei、guanyu、zhangfei

  1. lpush brother liubei
  2. # [liubei]
  3. lpush brother guanyu zhangfei xiaoming
  4. # [xiaoming,zhangfei,guanyu,liubei]

从键为brother的列表右侧添加一个或多个数据,xiaohong,xiaobai,xiaohui

  1. rpush brother xiaohong
  2. # [xiaoming,zhangfei,guanyu,liubei,xiaohong]
  3. rpush brother xiaobai xiaohui
  4. # [xiaoming,zhangfei,guanyu,liubei,xiaohong,xiaobai,xiaohui]

从key=brother,key=xiaohong的列表位置左侧添加一个数据,xiaoA,xiaoB

  1. linsert brother before xiaohong xiaoA
  2. # [xiaoming,zhangfei,guanyu,liubei,xiaoA,xiaohong,xiaobai,xiaohui]
  3. linsert brother before xiaohong xiaoB
  4. # [xiaoming,zhangfei,guanyu,liubei,xiaoA,xiaoB,xiaohong,xiaobai,xiaohui]

从key=brother,key=xiaohong的列表位置右侧添加一个数据,xiaoC,xiaoD

  1. linsert brother after xiaohong xiaoC
  2. # [xiaoming,zhangfei,guanyu,liubei,xiaoA,xiaohong,xiaoC,xiaobai,xiaohui]
  3. linsert brother after xiaohong xiaoD
  4. # [xiaoming,zhangfei,guanyu,liubei,xiaoA,xiaohong,xiaoD,xiaoC,xiaobai,xiaohui]

注意:当列表如果存在多个成员值一致的情况下,默认只识别第一个。

  1. 127.0.0.1:6379> linsert brother before xiaoA xiaohong
  2. # [xiaoming,zhangfei,guanyu,liubei,xiaohong,xiaoA,xiaohong,xiaoD,xiaoC,xiaobai,xiaohui]
  3. 127.0.0.1:6379> linsert brother before xiaohong xiaoE
  4. # [xiaoming,zhangfei,guanyu,liubei,xiaoE,xiaohong,xiaoA,xiaohong,xiaoD,xiaoC,xiaobai,xiaohui]
  5. 127.0.0.1:6379> linsert brother after xiaohong xiaoF
  6. # [xiaoming,zhangfei,guanyu,liubei,xiaoE,xiaohong,xiaoF,xiaoA,xiaohong,xiaoD,xiaoC,xiaobai,xiaohui]

设置指定索引位置成员的值

  1. lset key index value
  2. # 注意:
  3. # redis的列表也有索引,从左往右,从0开始,逐一递增,第1个元素下标为0
  4. # 索引可以是负数,表示尾部开始计数,如`-1`表示最后1个元素

修改键为brother的列表中下标为4的元素值为xiaohongmao

  1. lset brother 4 xiaohonghong

删除指定成员

  1. lrem key count value
  2. # 注意:
  3. # count表示删除的数量,value表示要删除的成员。该命令默认表示将列表从左侧前count个value的元素移除
  4. # count==0,表示删除列表所有值为value的成员
  5. # count >0,表示删除列表左侧开始的前count个value成员
  6. # count <0,表示删除列表右侧开始的前count个value成员

redis - 图23

获取列表成员

根据指定的索引获取成员的值

  1. lindex key index

获取brother下标为2以及-2的成员

  1. lindex brother 2
  2. lindex brother -2

移除并获取列表的第一个成员或最后一个成员

  1. lpop key # 第一个成员出列
  2. rpop key # 最后一个成员出列

获取并移除brother中的第一个成员

  1. lpop brother
  2. # 开发中往往使用rpush和lpop实现队列的数据结构->实现入列和出列

获取列表的切片

闭区间[包括stop]

  1. lrange key start stop

操作:

  1. # 获取btother的全部成员
  2. lrange brother 0 -1
  3. # 获取brother的前2个成员
  4. lrange brother 0 1

获取列表的长度

  1. llen key

获取brother列表的成员个数

  1. llen brother

获取哈希的所有成员域值对

  1. hgetall key

3.8 set

类似python里面的set无序集合, 成员是字符串string,重点就是去重和无序。

添加元素

key不存在,则表示新建集合,如果存在则表示给对应集合新增成员。

  1. sadd key member1 member2 ...

向键authors的集合中添加元素zhangsanlisiwangwu

  1. sadd authors zhangsan sili wangwu

获取集合的所有的成员

  1. smembers key

获取键authors的集合中所有元素

  1. smembers authors

获取集合的长度

  1. scard keys

获取s2集合的长度

  1. sadd s2 a c d e
  2. 127.0.0.1:6379> scard s2
  3. (integer) 4

随机获取一个或多个元素

  1. spop key [count=1]
  2. # 注意:
  3. # count为可选参数,不填则默认一个。被提取成员会从集合中被删除掉

随机获取s2集合的成员

  1. sadd s2 a c d e
  2. 127.0.0.1:6379> spop s2
  3. "d"
  4. 127.0.0.1:6379> spop s2
  5. "c"

删除指定元素

  1. srem key value

删除键authors的集合中元素wangwu

  1. srem authors wangwu

交集、差集和并集

  1. sinter key1 key2 key3 .... # 交集,比较多个集合中共同存在的成员
  2. sdiff key1 key2 key3 .... # 差集,比较多个集合中不同的成员
  3. sunion key1 key2 key3 .... # 并集,合并所有集合的成员,并去重
  1. sadd user:1 1 2 3 4 # user:1 = {1,2,3,4}
  2. sadd user:2 1 3 4 5 # user:2 = {1,3,4,5}
  3. sadd user:3 1 3 5 6 # user:3 = {1,3,5,6}
  4. sadd user:4 2 3 4 # user:4 = {2,3,4}
  5. # 交集
  6. 127.0.0.1:6379> sinter user:1 user:2
  7. 1) "1"
  8. 2) "3"
  9. 3) "4"
  10. 127.0.0.1:6379> sinter user:1 user:3
  11. 1) "1"
  12. 2) "3"
  13. 127.0.0.1:6379> sinter user:1 user:4
  14. 1) "2"
  15. 2) "3"
  16. 3) "4"
  17. 127.0.0.1:6379> sinter user:2 user:4
  18. 1) "3"
  19. 2) "4"
  20. # 并集
  21. 127.0.0.1:6379> sunion user:1 user:2 user:4
  22. 1) "1"
  23. 2) "2"
  24. 3) "3"
  25. 4) "4"
  26. 5) "5"
  27. # 差集
  28. 127.0.0.1:6379> sdiff user:2 user:3
  29. 1) "4" # 此时可以给user:3推荐4
  30. 127.0.0.1:6379> sdiff user:3 user:2
  31. 1) "6" # 此时可以给user:2推荐6
  32. 127.0.0.1:6379> sdiff user:1 user:3
  33. 1) "2"
  34. 2) "4"

3.9 zset

有序集合,去重并且根据score权重值来进行排序的。score从小到大排列。

添加成员

key如果不存在,则表示新建有序集合。

  1. zadd key score1 member1 score2 member2 score3 member3 ....

设置榜单achievements,设置成绩和用户名作为achievements的成员

  1. 127.0.0.1:6379> zadd achievements 61 xiaoming 62 xiaohong 83 xiaobai 78 xiaohei 87 xiaohui 99 xiaolan
  2. (integer) 6
  3. 127.0.0.1:6379> zadd achievements 85 xiaohuang
  4. (integer) 1
  5. 127.0.0.1:6379> zadd achievements 54 xiaoqing

给指定成员增加权重值

  1. zincrby key score member

给achievements中xiaobai增加10分

  1. 127.0.0.1:6379> ZINCRBY achievements 10 xiaobai
  2. "93

获取集合长度

  1. zcard key

获取users的长度

  1. zcard achievements

获取指定成员的权重值

  1. zscore key member

获取users中xiaoming的成绩

  1. 127.0.0.1:6379> zscore achievements xiaobai
  2. "93"
  3. 127.0.0.1:6379> zscore achievements xiaohong
  4. "62"
  5. 127.0.0.1:6379> zscore achievements xiaoming
  6. "61"

获取指定成员在集合中的排名

排名从0开始计算

  1. srank key member # score从小到大的排名
  2. zrevrank key member # score从大到小的排名

获取achievements中xiaohei的分数排名,从大到小

  1. 127.0.0.1:6379> zrevrank achievements xiaohei
  2. (integer) 4

获取score在指定区间的所有成员数量

  1. zcount key min max

获取achievements从0~60分之间的人数[闭区间]

  1. 127.0.0.1:6379> zadd achievements 60 xiaolv
  2. (integer) 1
  3. 127.0.0.1:6379> zcount achievements 0 60
  4. (integer) 2
  5. 127.0.0.1:6379> zcount achievements 54 60
  6. (integer) 2

获取score在指定区间的所有成员

  1. zrangebyscore key min max # 按score进行从低往高排序获取指定score区间
  2. zrevrangebyscore key min max # 按score进行从高往低排序获取指定score区间
  3. zrange key start stop # 按scoer进行从低往高排序获取指定索引区间
  4. zrevrange key start stop # 按scoer进行从高往低排序获取指定索引区间

获取users中60-70之间的数据

  1. 127.0.0.1:6379> zrangebyscore achievements 60 90
  2. 1) "xiaolv"
  3. 2) "xiaoming"
  4. 3) "xiaohong"
  5. 4) "xiaohei"
  6. 5) "xiaohuang"
  7. 6) "xiaohui"
  8. 127.0.0.1:6379> zrangebyscore achievements 60 80
  9. 1) "xiaolv"
  10. 2) "xiaoming"
  11. 3) "xiaohong"
  12. 4) "xiaohei"
  1. # 获取achievements中分数最低的3个数据
  2. 127.0.0.1:6379> zrange achievements 0 2
  3. 1) "xiaoqing"
  4. 2) "xiaolv"
  5. 3) "xiaoming"
  6. # 获取achievements中分数最高的3个数据
  7. 127.0.0.1:6379> zrevrange achievements 0 2
  8. 1) "xiaolan"
  9. 2) "xiaobai"
  10. 3) "xiaohui"

删除成员

  1. zrem key member1 member2 member3 ....

从achievements中删除xiaoming的数据

  1. zrem achievements xiaoming

删除指定数量的成员

  1. # 删除指定数量的成员,从最低score开始删除
  2. zpopmin key [count]
  3. # 删除指定数量的成员,从最高score开始删除
  4. zpopmax key [count]

例子:

  1. # 从achievements中提取并删除成绩最低的2个数据
  2. 127.0.0.1:6379> zpopmin achievements 2
  3. 1) "xiaoqing"
  4. 2) "54"
  5. 3) "xiaolv"
  6. 4) "60"
  7. # 从achievements中提取并删除成绩最高的2个数据
  8. 127.0.0.1:6379> zpopmax achievements 2
  9. 1) "xiaolan"
  10. 2) "99"
  11. 3) "xiaobai"
  12. 4) "93"

3.10 各种数据类型在开发中的常用业务场景

  1. 针对各种数据类型它们的特性,使用场景如下:
  2. 字符串string: 用于保存一些项目中的普通数据,只要键值对的都可以保存,例如,保存 session/jwt,定时记录状态,倒计时、验证码、防灌水答案
  3. 哈希hash:用于保存项目中的一些对象结构/字典数据,但是不能保存多维的字典,例如,商城的购物车,文章信息,json结构数据
  4. 列表list:用于保存项目中的列表数据,但是也不能保存多维的列表,例如,消息队列,秒杀系统,排队,浏览历史
  5. 无序集合set: 用于保存项目中的一些不能重复的数据,可以用于过滤,例如,候选人名单, 作者名单,
  6. 有序集合zset:用于保存项目中一些不能重复,但是需要进行排序的数据, 例如:分数排行榜, 海选人排行榜,热搜排行,

开发中,redis常用的业务场景:

  1. 数据缓存、
  2. 分布式数据共享、
  3. 计数器、
  4. 限流、
  5. 位统计(用户打卡、签到)、
  6. 购物车、
  7. 消息队列、
  8. 抽奖奖品池、
  9. 排行榜单(搜索排名)、
  10. 用户关系记录[收藏、点赞、关注、好友、拉黑]、

开发中,针对redis的使用,python中一般常用的redis模块有:pyredis(同步),aioredis(异步)。

  1. pip install py-redis
  2. pip install aioredis

3.11 python操作redis

这2个模块提供给开发者的使用方式都是一致的。都是以redis命令作为函数名,命令后面的参数作为函数的参数。只有一个特殊:del,del在python属于关键字,所以改成delete即可。

基本使用

  1. from redis import Redis, StrictRedis
  2. if __name__ == '__main__':
  3. # 连接redis的写法有2种:
  4. # url="redis://:密码@IP:端口/数据库编号"
  5. redis = Redis.from_url(url="redis://:@127.0.0.1:6379/0")
  6. # redis = Redis(host="127.0.0.1", port=6379, password="", db=0)
  7. # # 字符串
  8. # # set name xiaoming
  9. # redis.set("name", "xiaoming")
  10. # # setex sms_13312345678 30 500021
  11. # mobile = 13312345678
  12. # redis.setex(f"sms_{mobile}", 30, "500021")
  13. #
  14. # # get name
  15. # ret = redis.get("name")
  16. # # redis中最基本的数据类型是字符串,但是这种字符串是bytes,所以对于python而言,读取出来的字符串数据还要decode才能使用
  17. # print(ret, ret.decode())
  18. # # 提取数据,键如果不存在,则返回结果为None
  19. # code_bytes = redis.get(f"sms_{mobile}")
  20. # print(code_bytes)
  21. # if code_bytes: # 判断只有获取到数据才需要decode解码
  22. # print(code_bytes.decode())
  23. # 设置字典,单个成员
  24. # hset user name xiaoming
  25. # redis.hset("user", "name", "xiaoming")
  26. # # 设置字典,多个成员
  27. # # hset user name xiaohong age 12 sex 1
  28. # data = {
  29. # "name": "xiaohong",
  30. # "age": 12,
  31. # "sex": 1
  32. # }
  33. # redis.hset("user", mapping=data)
  34. # # 获取字典所有成员,字典的所有成员都是键值对,而键值对也是bytes类型,所以需要推导式进行转换
  35. # ret = redis.hgetall("user")
  36. # print(ret) # {b'name': b'xiaohong', b'age': b'12', b'sex': b'1'}
  37. # data = {key.decode(): value.decode() for (key, value) in ret.items()}
  38. # print(data)
  39. # # 获取当前仓库的所有的key
  40. ret = redis.keys("*")
  41. print(ret)
  42. # 删除key
  43. if len(ret) > 0:
  44. redis.delete(ret[0])