Redis必备知识手册

Redis必备知识手册

一、认识之初

1、什么是Redis

Remote Dictionary Server(Redis) 是一个由 Salvatore Sanfilippo 写的基于 key-value(键值存储系统)的一款内存高速缓存数据库,使用C语言编写。Redis 提供了一些丰富的数据结构,包括 lists、sets、ordered sets 以及 hashes ,当然还有和 Memcached 一样的 strings 结构。Redis 当然还包括了对这些数据结构的丰富操作。

Redis 常被称作是一款数据结构服务器(data structure server)。Redis 的键值可以包括字符串(strings)类型,同时它还包括哈希(hashes)、列表(lists)、集合(sets)和 有序集合(sorted sets)等数据类型。

对于这些数据类型,你可以执行原子操作。例如:对字符串进行附加操作(append);递增哈希中的值;向列表中增加元素;计算集合的交集、并集与差集等。

2、Redis的优点

  • 性能极高 : Redis能读的速度是110000次/s,写的速度是81000次/s 。
  • 丰富的数据类型:Redis 支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
  • 原子:Redis 的所有操作都是原子性的,同时 Redis 还支持对几个操作全并后的原子性执行。
  • 丰富的特性:Redis 还支持 publish/subscribe, 通知, key 过期等等特性。

使用 Redis 只需要下载对应的软件包开箱即用,截止目前(2019.1)最新的版本有 5.* 可用

3、Redis应用场景

  • 用来做缓存(ehcache/memcached)——redis的所有数据是放在内存中的(内存数据库)
  • 可以在某些特定应用场景下替代传统数据库——比如社交类的应用
  • 在一些大型系统中,巧妙地实现一些特定的功能:session共享、购物车
  • 只要你有丰富的想象力,redis可以用在可以给你无限的惊喜…….

在互联网公司的应用:

  • String:缓存、限流、计时器、分布式锁、分布式Session
  • Hash:存储用户信息、用户页面访问量、组合查询
  • List:微博关注人时间列表、简单队列
  • Set:赞、踩、标签、好友关系
  • Zset:排行榜

二、Redis安装、配置与连接

1、Linux环境

# 安装redis
sudo apt-get install redis-server

# 进入
redis-cli

具体使用,如:启动,配置绑定ip远程连接等等。(选择"数据库"下的"Redis")

2、windows环境

下载官网
安装时要添加到path路径

启动 Redis-server

redis-server  

保持此终端的运行,重开一个终端.

启动客户端

redis-cli

127.0.0.1:6379>

密码设置:

设置redis.windows.conf

#443行,requirepass修改为:
requirepass [自己设置的密码]

# 或者
config set requirepass [你自己设置的密码]

默认端口:
6379

开启服务与关闭服务
方法一:本地模式(无需维持服务器终端)

#Redis作为服务启动,开启服务:
redis-server --service-start

#启动数据库,指定本地主机:
redis-cli.exe -h 127.0.0.1 -p 6379

#其他指令
关闭服务:redis-server --service-stop
卸载服务:redis-server --service-uninstall

方法二:命令模式

#开启服务,该cmd作为服务,一直运行,不可关闭
redis-server redis.windows.conf

#开打一个新的终端,启动数据库,指定本地主机:
redis-cli.exe -h 127.0.0.1 -p 6379

#关闭服务开启的cmd窗口则关闭了服务

远程连接:

  • 注释掉redis.windows-service.conf 中的bind 127.0.0.1(只对127.0.0.1进行监听)这一行,在前面加#,注销调后即对所有ip进行监听 。
  • 同文件中将protected-mode yes 改成 protected-mode no
  • 保存并重启redis服务
  • 保证本机和远程电脑ping的通的情况下,在本机redis目录下打开PowerShell或者cmd,输入命令
redis-cli -h XXX -p XXX [-a XXX]

注意这里不能直接打开reids-cli.exe操作

三、Redis值的类型

Redis 不仅仅是简单的 key-value 存储器,同时也是一种 data structures server。传统的 key-value 是指支持使用一个 key 字符串来索引 value 字符串的存储,而 Redis 中,value 不仅仅支持字符串,还支持更多的复杂结构,包括列表、集合、哈希表等。

现在我们一一讲解:Redis keys 是采用二进制安全,这就意味着你可以使用任何二进制序列作为重点,比如:“foo” 可以联系一个 JPEG 文件;空字符串也是一个有效的密钥。

Redis 字符串是二进制安全的,这意味着一个 Redis 字符串能包含任意类型的数据,例如: 一张经过 base64 编码的图片或者一个序列化的对象。通过这样的方式,Redis 的字符串可以支持任意形式的数据,但是对于过大的文件不适合存入 redis,一方面系统内存有限,另外一方面字符串类型的值最多能存储 512M 字节的内容。

Redis的5种数据类型

  • String
  • hash
  • list
  • set
  • zset

针对这几种数据类型,数据库操作的全部命令

1、Redis Strings - String字符串

Redis的最基本类型,最大能存储512M的数据。它的类型是二进制的,可以存储任何数据,如:数字、图片、序列化对象等。

一个key对应一个value

1.1 简单指令速查:

指令含义
set key value设置值
get key获取值
mset key1 value1 key2 value2 …设置多个值
mget key1 key2 key3获取多个值
flushdb清空当前db
type key查看当前key数据类型

1.2 详细指令:

(1)设置键值

设置键值语句例子
设置单个键值set key valueset name lyh
设置多个键值mset key value[key value key …]mset name lyh age 21
设置值及过期时间(单位:s)setex key seconds valuesetex age 10 21
查看有效时间ttl keyttl age
key不存在时才设置key值setnx key valuesetnx name liyuhong

(2)key的操作

key的操作语句例子
根据键值获取值,不存在则返回None(null 0 nil)get keyget name
获取多个key值mget key1 [key2 …]mget name age
返回key种,字符串值的子字符getrange key start endgetrange name 0 2
修改key对应的value值,并返回旧value值getset key valuegetset name liyuhong
判断key是否存在exists keyexists name
查看key对应的value类型type keytype name
修改key的名称,当新的key名不存在时(与其他名称无冲突)rename key newkeyrename name myname(当myname已存在,则不会发生修改)
重命key名(冲突则覆盖,以新的key为准)rename key newkeyrename name myname
将key移动到指定的数据库move key dbnummove name 1(将以name为key的键值对移动到库1中)
随机返回一个keyrangdomkeyrandomkey直接使用
与生存时间相关操作语句例子
直接设置值及过期时间(单位:s)setex key seconds valuesetex age 10 21
设置已存在的key的过期时间(单位:s)expire key secondsexpire name 10
查看有效时间(单位:s)ttl namettl name
查看有效时间(单位:ms)pttl keypttl name
移除key的过期时间,将key持久化(ttl作废)persist keypersist name
删除key操作
删除键及对应的值del key [key…]
flushdb删除当前数据库中所有的key
flushall删除所有数据库中的key

(3)运算
条件:值是字符串类型的数字

运算语句例子
将key对应的value值+1incr keyincr age
将key对应的value值-1decr keydecr age
将key对应的value值+整数incrby key intnumincrby age 3
将key对应的value值-整数decr key intnumdecr age 3

(4)其他

其他用法语句例子
字符串形式追加value的值append key valueappend age 100
获取value长度strlen keystrlen name
删除del keydel name

(5)key键的正则

key键的正则操作语句例子
查询所有符合给定模式(正则)的keykeys * / keys *o* / keys t???匹配任意一个,*匹配0个1个多个
查询所有符合原子表的模式f[io]nd / f[^io] / f[a-z]nd[xx]匹配任意一个xx,[^xx]匹配除xx以外,[x-y]匹配从x到y

**注意:**set 命令将取代现有的任何已经存在的 key。set 命令还有一个提供附加参数的选项,我们能够让 set 命令只有在没有相同 key 的情况下成功,反之亦然,可以让 set 命令在有相同 key 值的情况下成功:

set mykey newval nx
set mykey newval xx

set完整内容:
在这里插入图片描述
参数含义:

  • set : 设置一个键值对内容
  • key : 键名
  • value : 值内容
  • [EX seconds] : 设置指定的过期时间,以秒为单位。(可选) set a 5 EX 5
  • [PX milliseconds] : 设置指定的过期时间,以毫秒为单位。(可选)
  • NX : 只有键key不存在的时候才会设置key的值
  • XX : 只有键key存在的时候才会设置key的值

2、Redis Hashes - Hash哈希

Redis Hashes 是字符串字段和字符串值之间的映射,因此它们是展现对象的完美数据类型。例如一个有名、姓、年龄等等属性的用户:一个带有一些字段的 hash 仅仅需要一块很小的空间存储,因此你可以存储数以百万计的对象在一个小的 Redis 实例中。哈希主要用来表现对象,它们有能力存储很多对象,因此你可以将哈希用于许多其它的任务。

hash用于存储对象
{
name:liyuhong
age:21
}
Redis的hash是一个键值对的集合

2.1 简单指令速查

指令含义
hset key field value设置散列值
hget key field获取散列值
hmset key field value [field value …]设置多对散列值
hgetall key获取所有散列值

2.2 详细指令

(1)设置哈希值

操作语句例子
设置单个值hset key field valuehset myinfo name liyuhong
设置多个值hmset key field value [field value …]hmset myinfo name lyh age 21
为哈希表key中指定的字段的整数值赋予增量incrementhincrby key field incrementhincrby myinfo age 10
字段field不存在时,设置哈希表字段的值hsetnx key field valuehsetnx myinfo name lyh

(2)获取

操作语句例子
获取一个属性的值hget key fieldhget myinfo name
获取多个属性的值hmget key field [field …]hmget myinfo name age
获取所有字段和值hgetall keyhgetall myinfo
获取所有字段hkeys keyhkeys myinfo
获取所有的值hvals keyhvals myinfo
返回包含数据的个数hlen keyhlen myinfo

(3)其他

操作语句例子
判断字段是否存在,1存在,0不存在hexists key fieldhexists myinfo name
删除字段及值hdel key field [field]hdel myinfo name age
返回值的字符串长度hstrlen key fieldhstrlen key name

3、Redis Lists - list列表

Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边),lpush 命令插入一个新的元素到头部,而 rpush 命令插入一个新元素到尾部。当这两个操作中的任一操作在一个空的 Key 上执行时就会创建一个新的列表。相似的,如果一个列表操作清空一个列表,那么对应的 key 将被从 key 空间删除。

3.1 简单指令速查

简单指令速查:

指令含义
lpush/rpush mylist value1 value2 …队列左边或者右边增加内容
lrange mylist 0 -1获取指定长度的内容

在这里插入图片描述
注意:lrange 需要两个索引,0 表示 list 开头第一个,-1 表示 list 的倒数第一个,即最后一个。-2 则是 list 的倒数第二个,以此类推。

这些命令都是可变的命令,也就是说你可以一次加入多个元素放入 list:

rpush mylist 1 2 3 4 5 "foo bar"
lrange mylist 0 -1

3.2 详细指令

(1)设置列表

操作语句例子
在头部插入Ipush key value [value …]Ipush mylist 1 2 3
将一个值插入到已存在的列表头部,列表不存在,操作无效lpush key valuelpush mylist 4
在一个元素value1的前 / 后插入新元素value2linsert key before / after value1 value2linsert mylist before 3 77
在尾部插入rpush key value [value …rpush mylist 5 6 7
为已存在的列表添加值rpush key valuerpushx mylist 9
更改索引对应的值lset index valuelset mylist 0 1(将索引0对应的值更改为1)
返回列表中索引对应的值lindex key indexlindex mylist 0
key存在时才插入lpushx key value
key存在时才插入rpushx key value

(2)获取

操作语句例子
移除并返回key对应的list的第一个元素lpop keylpop mylist
移除并返回key对应的list的最后一个元素rpop keyrpop mylist
返回存储在key的列表中指定范围的元素lrange key start endlrange mylist 0 -1(返回所有元素)

(3)其他

其他操作语句例子
裁剪列表,改为原列表的子集ltrim key strat endltrim mylist 1 -1
返回存储在key里的list的长度llen keyllen mylist

一个列表最多可以包含 4294967295(2 的 32 次方减一) 个元素,这意味着它可以容纳海量的信息,最终瓶颈一般都取决于服务器内存大小。

事实上,在高级的企业架构当中,会把缓存服务器分离开来,因为数据库服务器和缓存服务器的特点各异,比如对于数据库服务器应该用更快、更大的硬盘,而缓存专用服务器则偏向内存性能,一般都是 64GB 起步。

3.3 List 阻塞操作

理解阻塞操作对一些请求操作有很大的帮助,关于阻塞操作的作用,这里举一个例子。

假如你要去楼下买一个汉堡,一个汉堡需要花一定的时间才能做出来,非阻塞式的做法是去付完钱走人,过一段时间来看一下汉堡是否做好了,没好就先离开,过一会儿再来,而且要知道可能不止你一个人在买汉堡,在你离开的时候很可能别人会取走你的汉堡,这是很让人烦的事情。

阻塞式就不一样了,付完钱一直在那儿等着,不拿到汉堡不走人,并且后面来的人统统排队。

Redis 提供了阻塞式访问 brpop 和 blpop 命令。用户可以在获取数据不存在时阻塞请求队列,如果在时限内获得数据则立即返回,如果超时还没有数据则返回 null。

3.4 List 常见应用场景

分析 List 应用场景需要结合它的特点,List 元素是线性有序的,很容易就可以联想到聊天记录,你一言我一语都有先后,因此 List 很适合用来存储聊天记录等顺序结构的数据。

4、Redis Set - set 无序集合

Redis 集合(Set)是一个无序的字符串集合。你可以以 O(1) 的时间复杂度 (无论集合中有多少元素时间复杂度都是常量)完成添加、删除以及测试元素是否存在。

Redis 集合拥有令人满意的不允许包含相同成员的属性,多次添加相同的元素,最终在集合里只会有一个元素,这意味着它可以非常方便地对数据进行去重操作,一个 Redis 集合的非常有趣的事情是它支持一些服务端的命令从现有的集合出发去进行集合运算,因此你可以在非常短的时间内进行合并(unions), 求交集(intersections), 找出不同的元素(differences of sets)。

无序集合,元素类型为string类型,具有:唯一性、不重复性、无序性
{a,b}

4.1 简单指令速查

简单指令速查:

指令含义
sadd/srem key value1 value2添加/删除元素
smembers key返回该集合的所有成员

4.2 详细指令

(1) 设置集合

操作语句例子
创建集合、添加元素sadd key member [member …]sadd myset a b c d

(2)获取

操作语句例子
返回key集合中所有元素smembers keysmembers myset
返回集合元素个数scard keyscard myset
返回集合中一个或多个随机数srandmember key [count]srandmember myset(默认返回一个随机元素)
随机移除并返回集合中的一个元素spop keyspop myset
移除集合中一个或多个成员srem key member [member …]srem myset a b c d

3.集合中的其他操作

操作语句
求多个集合的交集sinter key1 key2
求多个集合的差集sdiff key1 key2
求多个集合的并集sunion key1 key2
判断元素是否在集合中,是1,不是0sismember key member

5、Redis set - zset 有序集合

Redis 有序集合与普通集合非常相似,是一个没有重复元素的字符串集合。不同之处是有序集合的每一个成员都关联了一个权值,这个权值被用来按照从最低分到最高分的方式排序集合中的成员。集合的成员是唯一的,但是权值可以是重复的。

使用有序集合你可以以非常快的速度(O(log(N)))添加、删除和更新元素。因为元素是有序的, 所以你也可以很快的根据权值(score)或者次序(position)来获取一个范围的元素。访问有序集合的中间元素也是非常快的,因此你能够使用有序集合作为一个没有重复成员的智能列表。在有序集合中,你可以很快捷的访问一切你需要的东西:有序的元素,快速的存在性测试,快速访问集合的中间元素!简而言之使用有序集合你可以完成许多对性能有极端要求的任务,而那些任务使用其它类型的数据库真的是很难完成的。

zadd 与 sadd 类似,但是在元素之前多了一个参数,这个参数便是用于排序的。形成一个有序的集合。

> zadd hackers 1940 "Alan Kay"
> zadd hackers 1957 "Sophie Wilson"
> zadd hackers 1953 "Richard Stallman"
> zadd hackers 1949 "Anita Borg"
> zadd hackers 1965 "Yukihiro Matsumoto"
> zadd hackers 1914 "Hedy Lamarr"
> zadd hackers 1916 "Claude Shannon"
> zadd hackers 1969 "Linus Torvalds"
> zadd hackers 1912 "Alan Turing"

概述:

  1. 有序集合,元素类型为String,元素具有唯一性
  2. 每个元素都会关联一个score(表示权重),通过权重的大小进行排序,元素的score是可以相同的

5.1 简单指令速查

简单指令速查:

指令含义
添加有序集合zadd key score member [score member …]
正序返回指定范围的元素zrange key start end

5.2 详细指令

(1).设置

操作语句例子
添加有序集合zadd key score member [score member …]zadd myzset 1 a 2 c 3 b
有序集合中对指定成员的权重增加incrememtzincrby key incrememt memberzincrby myzset 1 a

(2)获取

操作语句实例
正序返回指定范围的元素zrange key start endzrange myzset 0 -1
逆序返回指定范围的元素zrevrange key start endzrevrange myzset -1 0
返回元素个数zcard keyzcard myzset
返回有序集合key中,score在min和max之间的元素个数zcount key min maxzcount myzset 1 3
返回有序集合中,成员member的score值zscore key memberzscore myzset a

其他数据库指令

操作语句
选择数据库select num
查看当前库下所有键keys *
清除当前数据库flushdb
清除所有数据库flushall

在我们进入数据以后,默认存在0库中,可以通过select数据库编号(0-15)进行切换,这些编号的数据库都是固定的

四、管理操作

前面讲述了 Redis 的基本数据类型,接下来继续讲解 Redis 相关命令及管理操作。

在 Redis 中,命令大小写不敏感。

  • 适合全体类型的常用命令
  • Redis 时间相关命令
  • Redis 设置相关命令
  • 查询信息

1、适合全体类型的常用命令

启动 redis 服务和 redis-cli 命令界面继续后续实验:

sudo service redis-server start
redis-cli

1.1 EXISTS and DEL

exists key:判断一个 key 是否存在,存在返回 1,否则返回 0。

del key:删除某个 key,或是一系列 key,比如:del key1 key2 key3 key4。成功返回 1,失败返回 0(key 值不存在)。

> set mykey hello
> exists mykey
> del mykey
> exists mykey

操作截图:
在这里插入图片描述

1.2 TYPE and KEYS

type key:返回某个 key 元素的数据类型 (none:不存在,string:字符,list:列表,set:元组,zset:有序集合,hash:哈希),key 不存在返回空。

keys key—pattern:返回匹配的 key 列表,比如:keys foo* 表示查找 foo 开头的 keys。

> set mykey x
> type mykey
> keys my*
> del mykey
> keys my*
> type mykey

操作截图:
在这里插入图片描述

1.3 RANDOMKEY and CLEAR

randomkey:随机获得一个已经存在的 key,如果当前数据库为空,则返回空字符串。

> randomkey

操作截图:
在这里插入图片描述
clear:清除界面。

> clear

1.4 RENAME and RENAMENX

rename oldname newname:更改 key 的名字,新键如果存在将被覆盖。

renamenx oldname newname:更改 key 的名字,新键如果存在则更新失败。

比如这里 randomkey 结果为 mylist,将此 key 值更名为 newlist。

> randomkey
> rename mylist newlist
> exists mylist
> exists newlist

操作截图:
在这里插入图片描述

1.5 DBSIZE

dbsize:返回当前数据库的 key 的总数。

> dbsize

操作截图:
在这里插入图片描述

2、Redis 时间相关命令

下面我们将会学习 Redis 时间相关命令。

2.1 限定 key 生存时间

这同样是一个无视数据类型的命令,对于临时存储很有用处。避免进行大量的 DEL 操作。

expire:设置某个 key 的过期时间(秒),比如:expire bruce 1000 表示设置 bruce 这个 key 1000 秒后系统自动删除,注意:如果在还没有过期的时候,对值进行了改变,那么那个值会被清除。

> set key some-value
> expire key 10
> get key       (马上执行此命令)
> get key       (10s后执行此命令)

操作截图:
在这里插入图片描述
结果显示:执行 expire 命令后,马上 get 会显示 key 存在;10 秒后再 get 时,key 已经被自动删除。

2.2 查询 key 剩余生存时间

限时操作可以在 set 命令中实现,并且可用 ttl 命令查询 key 剩余生存时间。

ttl:查找某个 key 还有多长时间过期,返回时间单位为秒。

> set key 100 ex 30
> ttl key
> ttl key

操作截图:
在这里插入图片描述

2.3 清除 key

flushdb:清空当前数据库中的所有键。

flushall:清空所有数据库中的所有键。

> flushdb
> flushall

3、Redis 设置相关命令

Redis 有其配置文件,可以通过 client-command 窗口查看或者更改相关配置。下面介绍相关命令。

3.1 CONFIG GET and CONFIG SET

config get:用来读取运行 Redis 服务器的配置参数。

config set:用于更改运行 Redis 服务器的配置参数。

auth:认证密码。

下面针对 Redis 密码的示例:

> config get requirepass  # 查看密码
> config set requirepass 123456  # 设置密码为 123456
> config get requirepass  # 报错,没有认证
> auth 123456  # 认证密码
> config get requirepass

操作截图:
在这里插入图片描述
由结果可知,刚开始时 Reids 并未设置密码,密码查询结果为空。然后设置密码为 123456,再次查询报错。经过 auth 命令认证后,可正常查询。

可以通过修改 Redis 的配置文件 redis.conf 修改密码。

五、查询信息

info [section]:查询 Redis 相关信息。

info 命令可以查询 Redis 几乎所有的信息,其命令选项有如下:

  • server: Redis server 的常规信息
  • clients: Client 的连接选项
  • memory: 存储占用相关信息
  • persistence: RDB and AOF 相关信息
  • stats: 常规统计
  • replication: Master/Slave 请求信息
  • cpu: CPU 占用信息统计
  • cluster: Redis 集群信息
  • keyspace: 数据库信息统计
  • all: 返回所有信息
  • default: 返回常规设置信息

若命令参数为空,info 命令返回所有信息。

> info server

操作截图:
在这里插入图片描述
参考: http://redis.io/commands/config-resetstat

六、高级操作

前面学习了 Redis 的基础知识和基本命令,接下来继续讲解 Redis 的高级应用,包括:安全性设置,主从复制,事务处理,持久化机制,虚拟内存的使用。

知识点

  • 安全性
  • 主从复制
  • 事务处理
  • 持久化机制
  • 虚拟内存的使用

1、安全性

涉及到客户端连接是需要指定密码的(由于 redis 速度相当的快,一秒钟可以 150K 次的密码尝试,所以需要设置一个强度很大的密码)。

设置密码的方式有两种:

  • 使用 config set 命令的 requirepass 参数,具体格式为 config set requirepass “password”
  • 在 redis.conf 文件中设置 requirepass 属性,后面为密码。

输入认证的方式也有两种:

  • 登录时可以使用 redis-cli -a password
  • 登录后可以使用 auth password

1.1 设置密码

第一种密码设置方式在上一个实验中已经提到(在 CONFIG SET 命令讲解的实例),此处我们来看看第二种方式设置密码。

首先需要进入 Redis 的安装目录,然后修改配置文件 redis.conf。根据 grep 命令的结果,使用 vim 编辑器修改 “# requirepass foobared” 为 “requirepass test123”,然后保存退出。

sudo vim /etc/redis/redis.conf

编辑 redis.conf 的结果:
在这里插入图片描述
重启之后就需要验证密码了

2、主从复制

为了分担服务器压力,会在特定情况下部署多台服务器分别用于缓存的读和写操作,用于写操作的服务器称为主服务器,用于读操作的服务器称为从服务器。

从服务器通过 psync 操作同步主服务器的写操作,并按照一定的时间间隔更新主服务器上新写入的内容。

Redis 主从复制的过程:

  1. Slave 与 Master 建立连接,发送 psync 同步命令。
  2. Master 会启动一个后台进程,将数据库快照保存到文件中,同时 Master 主进程会开始收集新的写命令并缓存。
  3. 后台完成保存后,就将此文件发送给 Slave。
  4. Slave 将此文件保存到磁盘上。

Redis 主从复制特点:

  1. 可以拥有多个 Slave。
  2. 多个 Slave 可以连接同一个 Master 外,还可以连接到其它的 Slave。(当 Master 宕机后,相连的 Slave 转变为 Master)
  3. 主从复制不会阻塞 Master,在同步数据时, Master 可以继续处理 Client 请求。
  4. 提高了系统的可伸缩性。

从服务器的主要作用是响应客户端的数据请求,比如返回一篇博客信息。

上面说到了主从复制是不会阻塞 Master 的,就是说 Slave 在从 Master 复制数据时,Master 的删改插入等操作继续进行不受影响。

如果在同步过程中,主服务器修改了一篇博客,而同步到从服务器上的博客是修改前的。这时候就会出现时间差,即修改了博客过后,在访问网站的时候还是原来的数据,这是因为从服务器还未同步最新的更改,这也就意味着非阻塞式的同步只能应用于对读数据延迟接受度较高的场景。

要建立这样一个主从关系的缓存服务器,只需要在 Slave 端执行命令:

# SLAVEOF IPADDRESS:PORT
> SLAVEOF 127.0.0.1:6379

如果主服务器设置了连接密码,就需要在从服务器中事先设置好:

config set masterauth <password>

这样,当前服务器就作为 127.0.0.1:6379 下的一个从服务器,它将定期从该服务器复制数据到自身。

在以前的版本中(2.8 以前),你应该慎用 redis 的主从复制功能,因为它的同步机制效率低下,可以想象每一次短线重连都要复制主服务器上的全部数据,算上网络通讯所耗费的时间,反而可能达不到通过 redis 缓存来提升应用响应速度的效果。但是幸运的是,官方在 2.8 以后推出了解决方案,通过部分同步来解决大量的重复操作。

这需要主服务器和从服务器都至少达到 2.8 的版本要求。

3、事务处理

Redis 的事务处理比较简单。只能保证 client 发起的事务中的命令可以连续的执行,而且不会插入其它的 client 命令,当一个 client 在连接中发出 multi 命令时,这个连接就进入一个事务的上下文,该连接后续的命令不会执行,而是存放到一个队列中,当执行 exec 命令时,redis 会顺序的执行队列中的所有命令。

需要注意的是,redis 对于事务的处理方式比较特殊,它不会在事务过程中出错时恢复到之前的状态,这在实际应用中导致我们不能依赖 redis 的事务来保证数据一致性。

4、持久化设置

内存和磁盘的区别除了速度差别以外,还有就是内存中的数据会在重启之后消失,持久化的作用就是要将这些数据长久存到磁盘中以支持长久使用。

Redis 是一个支持持久化的内存数据库,Redis 需要经常将内存中的数据同步到磁盘来保证持久化。

Redis 支持两种持久化方式:

1、snapshotting(快照):将数据存放到文件里,默认方式。

是将内存中的数据以快照的方式写入到二进制文件中,默认文件 dump.rdb,可以通过配置设置自动做快照持久化的方式。可配置 Redis 在 n 秒内如果超过 m 个 key 被修改就自动保存快照。比如:

save 900 1:900 秒内如果超过 1 个 key 被修改,则发起快照保存。

save 300 10:300 秒内如果超过 10 个 key 被修改,则快照保存。

2、Append-only file(缩写为 aof):将读写操作存放到文件中。

由于快照方式在一定间隔时间做一次,所以如果 Redis 意外 down 掉的话,就会丢失最后一次快照后的所有修改。

aof 比快照方式有更好的持久化性,是由于使用 aof 时,redis 会将每一个收到的写命令都通过 write 函数写入到文件中,当 redis 启动时会通过重新执行文件中保存的写命令来在内存中重新建立整个数据库的内容。

由于 os 会在内核中缓存 write 做的修改,所以可能不是立即写到磁盘上,这样 aof 方式的持久化也还是有可能会丢失一部分数据。可以通过配置文件告诉 redis 我们想要通过 fsync 函数强制 os 写入到磁盘的时机。

配置文件中的可配置参数:

appendonly yes //启用 aof 持久化方式

# appendfsync always //收到写命令就立即写入磁盘,最慢,但是保证了数据的完整持久化

appendfsync everysec //每秒钟写入磁盘一次,在性能和持久化方面做了很好的折中

# appendfsync no //完全依赖 os,性能最好,持久化没有保证

在 redis-cli 的命令中,save 命令是将数据写入磁盘中。

> help save
> save

操作截图:
在这里插入图片描述
进一步阐述:

Redis有两种持久化方案,RDB(Redis DataBase)和AOP(Append Only File)
RDB和AOF
RDB:是redis默认的持久化方案。在指定的时间间隔内,执行指定次数的写操作,则会将内存中的数据写入到磁盘中。即在指定目录下生成一个dump.rdb文件。Redis重启会通过加载dump.rdb恢复数据。
AOF:默认不开启。他的出现是为了弥补RDB的不足(数据的不一致性),所以它采用日志的形式来记录每个写操作,并追加到文件中。Redis重启会根据日志文件的内容,将写命令从前到后执行一次已完成数据的恢复工作

(1)RDB持久化设置
默认情况下,redis在磁盘上创建名为dump.rdb的数据快照的二进制格式文件,可以通过配置文件,配置:每个N秒且数据集上至少有M个变化时创建快照、是否对数据进行压缩、快照的名称、存放快照的工作目录等。redis默认配置如下:

900秒后且至少一个key发生变化时创建快照
save 900 1
300秒后且至少10key发生变化时创建快照
save 300 10
60秒收 且至少10000key发生变化时创建快照
save 60 10000
创建快照时 对数据进行压缩
rdbcompression yes
快照名称
dbfilename dump.rdb

(2)AOP持久化设置
利用快照的持久化方式不是很可靠,当运行Redis的计算机停止工作、意外断电、意外杀掉了Redis的进程,那么最近写入Redis的数据将会丢失。AOF方式是一个替代的方案,用以最大限度的持久化数据,通过redis.config进行开启还是关闭:

关闭aof
appendonly no
开启aof
appendonly yes

七、用python操作redis

redis连接实例是线程安全的,可以直接将redis连接实例设置为一个全局变量,直接使用。如果需要另一个Redis实例(or Redis数据库)时,就需要重新创建redis连接实例来获取一个新的连接。同理,python的redis没有实现select命令。

1、安装、导入redis模块

# 安装
pip install redis

# 导入
import redis

2、连接方式

  1. StrictRedis实现大部分官方的命令。向后兼容旧版本的redis
  2. Redis是StrictRedis的子类

官方推荐使用StrictRedis
连接实例:

import redis
redis.Redis(host='127.0.0.1',password='密码',port=6379,db=0,decode_responses=True)
r = redis.StrictRedis(host='127.0.0.1',decode_responses=True)
print(r)

decode_responses=True获得的结果自动进行解码,写入的键值对中的value为str类型,否则,如果不添加参数写入的则为字节类型,需要手动解码res.decode(‘utf-8’)

3、连接池connection pool

概述:
管理一个redis server的所有连接,避免每次建立、释放连接的开销,默认每个redis实例都会维护一个自己的连接池,可以直接建立一个连接池,作为参数传递给redis,这样可以实现多个redis共享一个连接池

实例:

pool = redis.ConnectionPool(pool='127.0.0.1',db=0,port=6379,decode_responses=True)
r = redis.Redis(connection_pool=pool)
print(r)

4、python操作字符串string类型

4.1 set()

函数:
set(name, value, ex=None, px=None, nx=False, xx=False)

在Redis中设置值,默认,不存在则创建,存在则修改

参数:

ex,过期时间(秒)
px,过期时间(毫秒)
nx,如果设置为True,则只有name不存在时,当前set操作才执行
xx,如果设置为True,则只有name存在时,当前set操作才执行

ex,过期时间(秒) 这里过期时间是3秒,3秒后p,键food的值就变成None

连接

import redis
r = redis.Redis(host='127.0.0.1',db=0,decode_responses=True)

例子:
(1)set设置值

r.set('name','liyuhong')

(2)get获取值

print(r.get('name'))

(3)批量设置值mset

r.mset(age=18,sex='男',hobby='写代码')

(4)批量获取值mget

r.mget('name','age','sex','hobby')

(5)设置新值,打印原值getset

print(t.getset('name','lyh'))

(6)返回对应值的长度strlen

print(r.strlen('name'))

(7)追加值append

r.append('age',18)
print(r.get('age'))

(8)查看类型type

print(r.type('name'))

4.2 setex()

函数:
setex(name, value, time)
参数:

time,过期时间(数字秒 或 timedelta对象)

例子:

import redis
import time

pool = redis.ConnectionPool(host='localhost', port=6379, decode_responses=True)
r = redis.Redis(connection_pool=pool)
r.setex("fruit2", "orange", 5)
time.sleep(5)
# 5秒后,取值就从orange变成None
print(r.get('fruit2')) 

4.2 setnx()

函数:
setnx(name, value)
设置值,只有name不存在时,执行设置操作(添加)

例子:

print(r.setnx('fruit1', 'banana'))  # fruit1不存在,输出为True

4.3 psetex()

函数:
psetex(name, time_ms, value)
设置值

参数:
time_ms,过期时间(数字毫秒 或 timedelta对象)

例子:

r.psetex("fruit3", 5000, "apple")
time.sleep(5)
print(r.get('fruit3'))  # 5000毫秒后,取值就从apple变成None

4.4 mset()

函数:
mset(*args, **kwargs)
批量设置值

例子:

r.mset({'k1': 'v1', 'k2': 'v2'})
print(r.mget("k1", "k2"))   # 一次取出多个键对应的值
print(r.mget("k1"))

4.5 mget()

函数:
mset(*args, **kwargs)
批量获取值

例子:

print(r.mget('k1', 'k2'))
print(r.mget(['k1', 'k2']))
# 将目前redis缓存中的键对应的值批量取出来
print(r.mget("fruit", "fruit1", "fruit2", "k1", "k2"))  

4.6 getrange()

函数:
getrange(key, start, end)
获取子序列(根据字节获取,非字符)

参数:
name,Redis 的 name
start,起始位置(字节)
end,结束位置(字节)

例子:

r.set("cn_name", "马可波罗") # 汉字
# 取索引号是0-2 前3位的字节 马 切片操作 (一个汉字3个字节 1个字母一个字节 每个字节8bit)
print(r.getrange("cn_name", 0, 2))
# 取所有的字节 马可波罗 切片操作
print(r.getrange("cn_name", 0, -1)) 
# 字母
r.set("en_name","liuxing") 
# 取索引号是0-2 前3位的字节 liu 切片操作 (一个汉字3个字节 1个字母一个字节 每个字节8bit)
print(r.getrange("en_name", 0, 2))
# 取所有的字节 liuxing 切片操作
print(r.getrange("en_name", 0, -1))

4.7 setrange()

函数:
setrange(name, offset, value)
修改字符串内容,从指定字符串索引开始向后替换(新值太长时,则向后添加)

参数:
offset,字符串的索引,字节(一个汉字三个字节)
value,要设置的值

例子:

r.setrange("en_name", 1, "ccc")
# jccci 原始值是junxi 从索引号是1开始替换成ccc 变成 jccci
print(r.get("en_name"))   

4.8 strlen()

函数:
strlen(name)
返回name对应值的字节长度(一个汉字3个字节)

例子:

print(r.strlen("foo"))  # 4 'goo1'的长度是4

4.9 incr()

函数:
incr(self, name, amount=1)
自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。
参数:
name,Redis的name
amount,自增数(必须是整数)
注:同incrby

例子:

r.set("foo", 123)
print(r.mget("foo", "foo1", "foo2", "k1", "k2"))
r.incr("foo", amount=1)
print(r.mget("foo", "foo1", "foo2", "k1", "k2"))

应用场景 – 页面点击数
假定我们对一系列页面需要记录点击次数。例如论坛的每个帖子都要记录点击次数,而点击次数比回帖的次数的多得多。如果使用关系数据库来存储点击,可能存在大量的行级锁争用。所以,点击数的增加使用redis的INCR命令最好不过了。
当redis服务器启动时,可以从关系数据库读入点击数的初始值(12306这个页面被访问了34634次)

r.set("visit:12306:totals", 34634)
print(r.get("visit:12306:totals"))

每当有一个页面点击,则使用INCR增加点击数即可。

r.incr("visit:12306:totals")
r.incr("visit:12306:totals")

页面载入的时候则可直接获取这个值

print(r.get("visit:12306:totals"))

4.10 incrbyfloat()

函数:
incrbyfloat(self, name, amount=1.0)
自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。

参数:
name,Redis的name
amount,自增数(浮点型)

例子:

r.set("foo1", "123.0")
r.set("foo2", "221.0")
print(r.mget("foo1", "foo2"))
r.incrbyfloat("foo1", amount=2.0)
r.incrbyfloat("foo2", amount=3.0)
print(r.mget("foo1", "foo2"))

4.11 decr()

函数:
decr(self, name, amount=1)
自减 name对应的值,当name不存在时,则创建name=amount,否则,则自减。
参数:

name,Redis的name
amount,自减数(整数)

例子:

r.decr("foo4", amount=3) # 递减3
r.decr("foo1", amount=1) # 递减1
print(r.mget("foo1", "foo4"))

4.12 append()

函数:
append(key, value)
在redis name对应的值后面追加内容
参数:

key, redis的name
value, 要追加的字符串

例子:

r.append("name", "haha")    # 在name对应的值junxi后面追加字符串haha
print(r.mget("name"))

5、python操作哈希hash类型

5.1 hset()

单个增加–修改,没有就新增,有的话就修改
hset(name, key, value)
name对应的hash中设置一个键值对(不存在,则创建;否则,修改)

参数:

name,redis的name
key,name对应的hash中的key
value,name对应的hash中的value

注:
hsetnx(name, key, value),当name对应的hash中不存在当前key时则创建(相当于添加)

例子:

import redis
import time

pool = redis.ConnectionPool(host='localhost', port=6379, decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.hset("hash1", "k1", "v1")
r.hset("hash1", "k2", "v2")
print(r.hkeys("hash1")) # 取hash中所有的key
print(r.hget("hash1", "k1"))    # 单个取hash的key对应的值
print(r.hmget("hash1", "k1", "k2")) # 多个取hash的key对应的值
r.hsetnx("hash1", "k2", "v3") # 只能新建
print(r.hget("hash1", "k2"))

5.2 hget() / hmget()

hget(name,key)
在name对应的hash中获取根据key获取value

hmget(name, keys, *args)
在name对应的hash中获取多个key的值

参数:

name,reids对应的name
keys,要获取key集合,如:['k1', 'k2', 'k3']
*args,要获取的key,如:k1,k2,k3

例子:

print(r.hget("hash2", "k2"))  # 单个取出"hash2"的key-k2对应的value
print(r.hmget("hash2", "k2", "k3"))  # 批量取出"hash2"的key-k2 k3对应的value --方式1
print(r.hmget("hash2", ["k2", "k3"]))  # 批量取出"hash2"的key-k2 k3对应的value --方式2

5.3 hgetall()

取出所有的键值对
hgetall(name)
获取name对应hash的所有键值

例子:

print(r.hgetall("hash1"))

5.4 hmset()

批量增加(取出)
hmset(name, mapping)
在name对应的hash中批量设置键值对
参数:

name,redis的name
mapping,字典,如:{'k1':'v1', 'k2': 'v2'}

例子:

r.hmset("hash2", {"k2": "v2", "k3": "v3"})

5.6 hlen()

得到所有键值对的格式 hash长度
hlen(name)
获取name对应的hash中键值对的个数

例子:

print(r.hlen("hash1"))

5.7 hkeys()

得到所有的keys(类似字典的取所有keys)
hkeys(name)
获取name对应的hash中所有的key的值

例子:

print(r.hkeys('mset'))

5.8 hvals()

得到所有的value(类似字典的取所有value)
hvals(name)
获取name对应的hash中所有的value的值

例子:

print(r.hvals("hash1"))

5.9 hdel()

删除键值对
hdel(name,*keys)
将name对应的hash中指定key的键值对删除

例子:

print(r.hgetall("hash1"))
r.hset("hash1", "k2", "v222")   # 修改已有的key k2
r.hset("hash1", "k11", "v1")   # 新增键值对 k11
r.hdel("hash1", "k1")    # 删除一个键值对
print(r.hgetall("hash1"))

5.10 hexists()

判断成员是否存在(类似字典的in)
hexists(name, key)
检查name对应的hash是否存在当前传入的key

例子:

print(r.hexists("hash1", "k4"))  # False 不存在
print(r.hexists("hash1", "k1"))  # True 存在

6、python操作列表list类型

6.1 lpush()

从头部添加元素
增加(类似于list的append,只是这里是从左边新增加)没有就新建
lpush(name,values)
在name对应的list中添加元素,每个新的元素都添加到列表的最左边

例子:

import redis
import time

pool = redis.ConnectionPool(host='localhost', port=6379, decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.lpush("list1", 11, 22, 33)
print(r.lrange('list1', 0, -1))

保存顺序为: 33,22,11

扩展:

r.rpush("list2", 11, 22, 33)  # 表示从右向左操作
print(r.llen("list2"))  # 列表长度
print(r.lrange("list2", 0, 3))  # 切片取出值,范围是索引号0-3

6.2 rpush()

从尾部添加元素
增加(从右边增加)没有就新建
rpush(name,values)

例子:

r.rpush("list2", 44, 55, 66)    # 在列表的右边,依次添加44,55,66
print(r.llen("list2"))  # 列表长度
print(r.lrange("list2", 0, -1)) # 切片取出值,范围是索引号0到-1(最后一个元素)

6.2 lpushx() / rpushx()

往已经有的name的列表的左边添加元素,没有的话无法创建
lpushx(name,value)
在name对应的list中添加元素,只有name已经存在时,值添加到列表的最左边

例子:

r.lpushx("list10", 10)   # 这里list10不存在
print(r.llen("list10"))  # 0
print(r.lrange("list10", 0, -1))  # []
r.lpushx("list2", 77)   # 这里"list2"之前已经存在,往列表最左边添加一个元素,一次只能添加一个
print(r.llen("list2"))  # 列表长度
print(r.lrange("list2", 0, -1)) # 切片取出值,范围是索引号0到-1(最后一个元素)

往已经有的name的列表的右边添加元素,没有的话无法创建

例子:

r.rpushx("list2", 99)   # 这里"foo_list1"之前已经存在,往列表最右边添加一个元素,一次只能添加一个
print(r.llen("list2"))  # 列表长度
print(r.lrange("list2", 0, -1)) # 切片取出值,范围是索引号0到-1(最后一个元素)

6.3 llen()

获取元素的个数
llen(name)

例子:

r.llen('list')

6.4 linsert()

插入值、新增(固定索引号位置插入元素)
linsert(name, where, refvalue, value))
在name对应的列表的某一个值前或后插入一个新值
参数:

name,redis的name
where,BEFORE或AFTER
refvalue,标杆值,即:在它前后插入数据
value,要插入的数据

例子:

r.linsert("list2", "before", "11", "00")   # 往列表中左边第一个出现的元素"11"前插入元素"00"
print(r.lrange("list2", 0, -1))   # 切片取出值,范围是索引号0-最后一个元素

6.5 lset()

修改(指定索引号进行修改)
r.lset(name, index, value)
对name对应的list中的某一个索引位置重新赋值
参数:

name,redis的name
index,list的索引位置
value,要设置的值

例子:

r.lset("list2", 0, -11)    # 把索引号是0的元素修改成-11
print(r.lrange("list2", 0, -1))

6.6 lrem()

删除(指定值进行删除)
r.lrem(name, value, num)
在name对应的list中删除指定的值

参数:

name,redis的name
value,要删除的值
num, num=0,删除列表中所有的指定值;
num=2,从前到后,删除2个; num=1,从前到后,删除左边第1个
num=-2,从后向前,删除2

例子:

r.lrem("list2", "11", 1)    # 将列表中左边第一次出现的"11"删除
print(r.lrange("list2", 0, -1))
r.lrem("list2", "99", -1)    # 将列表中右边第一次出现的"99"删除
print(r.lrange("list2", 0, -1))
r.lrem("list2", "22", 0)    # 将列表中所有的"22"删除
print(r.lrange("list2", 0, -1))

6.7 lpop()

删除并返回
lpop(name)
在name对应的列表的左侧获取第一个元素并在列表中移除,返回值则是第一个元素
rpop(name)
表示从右向左操作

例子:

r.lpop("list2")    # 删除列表最左边的元素,并且返回删除的元素
print(r.lrange("list2", 0, -1))
r.rpop("list2")    # 删除列表最右边的元素,并且返回删除的元素
print(r.lrange("list2", 0, -1))

6.8 lrem()

删除索引之外的值
ltrim(name, start, end)
在name对应的列表中移除没有在start-end索引之间的值
参数:

name,redis的name
start,索引的起始位置
end,索引结束位置

例子:

r.ltrim("list2", 0, 2)    # 删除索引号是0-2之外的元素,值保留索引号是0-2的元素
print(r.lrange("list2", 0, -1))

6.9 lindex()

取值( 根据索引号取值)
lindex(name, index)
在name对应的列表中根据索引获取列表元素

例子:

print(r.lindex("list2", 0))  # 取出索引号是0的值

6.10 lrange()

lrange分片获取元素
lrange(key, start, end)

例子:

print(r.lrange('list',0,-1))

7、python操作集合set类型

7.1 sadd()

sadd(name,values)
name对应的集合中添加元素

例子:

r.sadd("set1", 33, 44, 55, 66)  # 往集合中添加元素
print(r.scard("set1"))  # 集合的长度是4
print(r.smembers("set1"))   # 获取集合中所有的成员

7.2 scard()

获取元素个数,类似于len
scard(name)
获取name对应的集合中元素个数

例子:

print(r.scard("set1"))  # 集合的长度是4

7.3 smembers()

获取所有成员
smembers(name)
获取name对应的集合的所有成员

例子:

print(r.smembers("set1"))   # 获取集合中所有的成员

7.4 sscan()

获取集合中所有的成员–元组形式
sscan(name, cursor=0, match=None, count=None)

例子:

print(r.sscan("set1"))

7.5 sscan_iter()

获取集合中所有的成员–迭代器的方式
sscan_iter(name, match=None, count=None)
同字符串的操作,用于增量迭代分批获取元素,避免内存消耗太大

例子:

for i in r.sscan_iter("set1"):
   print(i)

7.6 sdiff()

sdiff(keys, *args)
在第一个name对应的集合中且不在其他name对应的集合的元素集合

例子:

r.sadd("set2", 11, 22, 33)
print(r.smembers("set1"))   # 获取集合中所有的成员
print(r.smembers("set2"))
print(r.sdiff("set1", "set2"))   # 在集合set1但是不在集合set2中
print(r.sdiff("set2", "set1"))   # 在集合set2但是不在集合set1中

7.7 sdiffstore()

差集–差集存在一个新的集合中
sdiffstore(dest, keys, *args)
获取第一个name对应的集合中且不在其他name对应的集合,再将其新加入到dest对应的集合中

例子:

r.sdiffstore("set3", "set1", "set2")    # 在集合set1但是不在集合set2中
print(r.smembers("set3"))   # 获取集合3中所有的成员

7.8 sinter()

sinter(keys, *args)
获取多一个name对应集合的交集

例子:

print(r.sinter("set1", "set2")) # 取2个集合的交集

7.9 sinterstore()

交集** 交集存在一个新的集合中
sinterstore(dest, keys, *args)
获取多一个name对应集合的并集,再将其加入到dest对应的集合中

例子:

print(r.sinterstore("set3", "set1", "set2")) # 取2个集合的交集
print(r.smembers("set3"))

7.10 sunion()

sunion(keys, *args)
获取多个name对应的集合的并集

例子:

print(r.sunion("set1", "set2")) # 取2个集合的并集

7.11 sunionstore()

并集–并集存在一个新的集合
sunionstore(dest,keys, *args)
获取多一个name对应的集合的并集,并将结果保存到dest对应的集合中

例子:

print(r.sunionstore("set3", "set1", "set2")) # 取2个集合的并集
print(r.smembers("set3"))

7.12 sismember()

判断是否是集合的成员 类似
sismember(name, value)
检查value是否是name对应的集合的成员,结果为True和False

例子:

print(r.sismember("set1", 33))  # 33是集合的成员
print(r.sismember("set1", 23))  # 23不是集合的成员

7.12 smove()

移动
smove(src, dst, value)
将某个成员从一个集合中移动到另外一个集合

例子:

r.smove("set1", "set2", 44)
print(r.smembers("set1"))
print(r.smembers("set2"))

7.12 spop()

删除** 随机删除并且返回被删除值
spop(name)
从集合移除一个成员,并将其返回,说明一下,集合是无序的,所有是随机删除的

例子:

print(r.spop("set2"))   # 这个删除的值是随机删除的,集合是无序的
print(r.smembers("set2"))

7.12 srem()

指定值删除
srem(name, values)
在name对应的集合中删除某些值

例子:

print(r.srem("set2", 11))   # 从集合中删除指定值 11
print(r.smembers("set2"))

8、python操作有序集合zset类型

Set操作,Set集合就是不允许重复的列表,本身是无序的
有序集合,在集合的基础上,为每元素排序;元素的排序需要根据另外一个值来进行比较,
所以,对于有序集合,每一个元素有两个值,即:值和分数,分数专门用来做排序。

8.1 zadd()

zadd(name, *args, **kwargs)
在name对应的有序集合中添加元素

例子:

import redis
import time

pool = redis.ConnectionPool(host='localhost', port=6379, decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.zadd("zset1", n1=11, n2=22)
r.zadd("zset2", 'm1', 22, 'm2', 44)
print(r.zcard("zset1")) # 集合长度
print(r.zcard("zset2")) # 集合长度
print(r.zrange("zset1", 0, -1))   # 获取有序集合中所有元素
print(r.zrange("zset2", 0, -1, withscores=True))   # 获取有序集合中所有元素和分数

8.2 zcard()

获取有序集合元素个数 类似于len
zcard(name)
获取name对应的有序集合元素的数量

例子:

print(r.zcard("zset1")) # 集合长度

8.3 zrange() / zrevrange()

获取所有元素
r.zrange( name, start, end, desc=False, withscores=False, score_cast_func=float)
按照索引范围获取name对应的有序集合的元素
参数:

name,redis的name
start,有序集合索引起始位置(非分数)
end,有序集合索引结束位置(非分数)
desc,排序规则,默认按照分数从小到大排序
withscores,是否获取元素的分数,默认只获取元素的值
score_cast_func,对分数进行数据转换的函数

从大到小排序(同zrange,集合是从大到小排序的)
zrevrange(name, start, end, withscores=False, score_cast_func=float)

例子:

print(r.zrevrange("zset1", 0, -1))    # 只获取元素,不显示分数
print(r.zrevrange("zset1", 0, -1, withscores=True)) # 获取有序集合中所有元素和分数,分数倒序

8.4 zrangebyscore()

按照分数范围获取name对应的有序集合的元素
zrangebyscore(name, min, max, start=None, num=None, withscores=False, score_cast_func=float)

例子:

for i in range(1, 30):
  element = 'n' + str(i)
  r.zadd("zset3", element, i)
print(r.zrangebyscore("zset3", 15, 25)) # # 在分数是15-25之间,取出符合条件的元素
print(r.zrangebyscore("zset3", 12, 22, withscores=True))    # 在分数是12-22之间,取出符合条件的元素(带分数)

8.5 zrevrangebyscore()

按照分数范围获取有序集合的元素并排序(默认从大到小排序)
zrevrangebyscore(name, max, min, start=None, num=None, withscores=False, score_cast_func=float)

例子:

print(r.zrevrangebyscore("zset3", 22, 11, withscores=True)) # 在分数是22-11之间,取出符合条件的元素 按照分数倒序

8.6 zscan()

获取所有元素–默认按照分数顺序排序
zscan(name, cursor=0, match=None, count=None, score_cast_func=float)

例子:

print(r.zscan("zset3"))

8.7 zrank() / zrevrank()

zrank(name, value)
获取某个值在 name对应的有序集合中的索引(从 0 开始)
zrevrank(name, value)
从大到小排序

例子:

print(r.zrank("zset3", "n1"))   # n1的索引号是0 这里按照分数顺序(从小到大)
print(r.zrank("zset3", "n6"))   # n6的索引号是1

print(r.zrevrank("zset3", "n1"))    # n1的索引号是29 这里安照分数倒序(从大到小)

8.8 zrem()

删除指定值
zrem(name, values)
删除name对应的有序集合中值是values的成员

例子:

r.zrem("zset3", "n3")   # 删除有序集合中的元素n3 删除单个
print(r.zrange("zset3", 0, -1))

8.9 zremrangebyrank()

范围删除,按照索引号来删除
zremrangebyrank(name, min, max)
根据排行范围删除

例子:

r.zremrangebyrank("zset3", 0, 1)  # 删除有序集合中的索引号是0, 1的元素
print(r.zrange("zset3", 0, -1))

8.10 zscan()

删除–根据分数范围删除
zremrangebyscore(name, min, max)
根据分数范围删除

例子:

r.zremrangebyscore("zset3", 11, 22)   # 删除有序集合中的分数是11-22的元素
print(r.zrange("zset3", 0, -1))

8.11 zscore()

获取值对应的分数
zscore(name, value)
获取name对应有序集合中 value 对应的分数

例子:

print(r.zscore("zset3", "n27"))   # 获取元素n27对应的分数27

9. 其他常用操作

删除
delete(*names)
根据删除redis中的任意数据类型(string、hash、list、set、有序set)

r.delete("gender")  # 删除key为gender的键值对

检查名字是否存在
exists(name)
检测redis的name是否存在,存在就是True,False 不存在

print(r.exists("zset1"))

模糊匹配
keys(pattern=’’) 根据模型获取redis的name 更多: KEYS * 匹配数据库中所有 key 。 KEYS h?llo 匹配 hello , hallo 和 hxllo 等。 KEYS hllo 匹配 hllo 和 heeeeello 等。
KEYS h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo

print(r.keys("foo*"))

设置超时时间
expire(name ,time)
为某个redis的某个name设置超时时间

r.lpush("list5", 11, 22)
r.expire("list5", time=3)
print(r.lrange("list5", 0, -1))
time.sleep(3)
print(r.lrange("list5", 0, -1))

重命名
rename(src, dst)
对redis的name重命名

r.lpush("list5", 11, 22)
r.rename("list5", "list5-1")

随机获取name
randomkey()
随机获取一个redis的name(不删除)

print(r.randomkey())

获取类型
type(name)
获取name对应值的类型

print(r.type("set1"))
print(r.type("hash2"))

查看所有元素
scan(cursor=0, match=None, count=None)

print(r.hscan("hash2"))
print(r.sscan("set3"))
print(r.zscan("zset2"))
print(r.getrange("foo1", 0, -1))
print(r.lrange("list2", 0, -1))
print(r.smembers("set3"))
print(r.zrange("zset3", 0, -1))
print(r.hgetall("hash1"))

查看所有元素–迭代器
scan_iter(match=None, count=None)

for i in r.hscan_iter("hash1"):
   print(i)

for i in r.sscan_iter("set3"):
   print(i)

for i in r.zscan_iter("zset3"):
   print(i)

其他方法

print(r.get('name'))    # 查询key为name的值
r.delete("gender")  # 删除key为gender的键值对
print(r.keys()) # 查询所有的Key
print(r.dbsize())   # 当前redis包含多少条数据
r.save()    # 执行"检查点"操作,将数据写回磁盘。保存时阻塞
# r.flushdb()        # 清空r中的所有数据

七、参考文档

Redis下载官网
官网文档 - 数据类型
博客 - Redis数据类型

七、更新时间

一次更新 2020/6/20

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值