码迷,mamicode.com
首页 > 其他好文 > 详细

3. Redis有哪些数据类型?

时间:2020-07-10 14:52:54      阅读:40      评论:0      收藏:0      [点我收藏+]

标签:存储结构   是什么   登录   提高   存在   python   port   com   get   

Redis的数据类型可谓是Redis的精华所在,同样的数据类型,但不同的值对应的存储结构也是不同的。比如:当你存储一个短字符串(小于44字节),实际存储的结构是embstr;长字符串对应的实际存储结构是raw,这样设计的目的就是为了更好的节约内存。

问题:Redis都有哪些数据类型呢?

最常用的数据类型有5种:String(字符串类型)、Hash(字典类型)、List(列表类型)、Set(集合类型)、ZSet(有序集合类型)。

那么这些数据类型都支持哪些操作呢?我们来一一介绍,当然Redis支持的数据结构已经不止这五种了,还有几个更高级的数据结构,我们后面介绍,但是最常用的还是上面五种。

不过在介绍之前需要安装Redis,安装过程比较简单就不说了,我这里就使用docker安装了,比较简单。

通过:docker run -d -p 6379:6379 --name redis redis后台启动。

启动之后,我们需要了解一下Redis的前置知识。

  • Redis默认有16个数据库,数据库名类似于数组的下表,从0到15,默认使用0号库。
  • select:切换数据库,比如select 1就表示切换到1号库
  • 统一密码管理,16个库都是一样的密码,要么都ok要么都连接不上。
  • 默认端口是6379

Redis字符串(String)

Redis的string类型,是一个key对应一个value。

set key value:给指定的key设置value

127.0.0.1:6379> set name hanser
OK
127.0.0.1:6379> set word "hello world"
OK  # 如果字符串之间有空格,我们可以使用双引号包起来

设置成功之后会返回一个ok,表示设置成功。除此之外,set还可以指定一些可选参数。

  • set key value ex 60:设置的时候指定过期时间为60秒,等价于setex key 60 value
  • set key value px 60:设置的时候指定过期时间为60毫秒,等价于psetex key 60 value
  • set key value nx:只有key不存在的时候才会设置,存在的话则会什么也不做,而如果不加nx则会覆盖。等价于setnx key value
  • set key value xx:只有key存在的时候才会设置,注意:对于xx来说,没有setxx key value

我们发现默认参数使用set足够了,因此未来可能会移除setex、psetex、setnx。另外,我们可以同一个key多次set,相当于对原来的值进行了覆盖。

get key:获取指定key对应的value

127.0.0.1:6379> get name
"hanser"
127.0.0.1:6379> get word
"hello world"
127.0.0.1:6379> get age
(nil)

如果key不存在,那么返回nil,也就是C语言中的NULL,python中的None、golang里的nil。存在的话,则返回key对应的value。

del key1 key2···:删除指定key,可以同时删除多个

127.0.0.1:6379> set age 28
OK
127.0.0.1:6379> get name
"hanser"
127.0.0.1:6379> get age
"28"  # 虽然我们设置的是一个数值,但是在Redis中都是字符串格式
127.0.0.1:6379> del name age gender
(integer) 2  # 会返回删除的key的个数,表示有效删除了两个,而gender不存在,因此无法删除一个不存在的key
127.0.0.1:6379> get name
(nil)
127.0.0.1:6379> get nil
(nil)
127.0.0.1:6379> 

append key value:追加

如果key存在,那么会将value的值追加到key对应的值的末尾,如果不存在,那么会重新设置,类似于set key value。

127.0.0.1:6379> set name han
OK
127.0.0.1:6379> set age 2
OK
127.0.0.1:6379> append name ser
(integer) 6  # 返回拼接之后的字符数量
127.0.0.1:6379> append age 8
(integer) 2  # 按照字符串的格式拼接
127.0.0.1:6379> get name
"hanser"
127.0.0.1:6379> get age
"28"
127.0.0.1:6379> append gender female
(integer) 6  # gender不存在,相当于重新设置,或者你理解为往一个空字符后面追加也行
127.0.0.1:6379> get gender
"female"
127.0.0.1:6379> 

strlen key:查看对应key的长度

127.0.0.1:6379> strlen name
(integer) 6
127.0.0.1:6379> strlen age
(integer) 2
127.0.0.1:6379> strlen not_exists
(integer) 0  # 不存在的key返回0
127.0.0.1:6379> 

incr key:为key存储的值自增1,必须可以转成整型,否则报错。如果不存在key,默认先设置该key值为0,然后自增1

127.0.0.1:6379> get age
"28"
127.0.0.1:6379> incr age
(integer) 29  # 返回自增后的结果
127.0.0.1:6379> get age
"29"
127.0.0.1:6379> incr age1 
(integer) 1
127.0.0.1:6379> get age1
"1"
127.0.0.1:6379> incr name
(error) ERR value is not an integer or out of range
127.0.0.1:6379> 

decr key:为key存储的值自减1,必须可以转成整型,否则报错。如果不存在key,默认先设置该key值为0,然后自减1

127.0.0.1:6379> decr age
(integer) 28
127.0.0.1:6379> decr age2
(integer) -1
127.0.0.1:6379> 

incrby key number:为key存储的值自增number,必须可以转成整型,否则报错,如果不存在的话,默认先将该值设置为0,然后自增number

127.0.0.1:6379> incrby age 20
(integer) 48
127.0.0.1:6379> incrby age3 5
(integer) 5
127.0.0.1:6379> 

decrby key number:为key存储的值自减number,必须可以转成整型,否则报错,如果不存在的话,默认先将该值设置为0,然后自减number

127.0.0.1:6379> decrby age 20
(integer) 28
127.0.0.1:6379> decrby age4 5
(integer) -5
127.0.0.1:6379> decrby age4 -5
(integer) 0  # 指定负数也是可以的,同理incrby也是如此
127.0.0.1:6379> 

getrange key start end:获取指定value的同时指定范围,第一个字符为0,最后一个为-1。注意:redis中的索引都是包含结尾的,不管是这里的getrange,还是后面的列表操作,索引都是包含两端的。

127.0.0.1:6379> get name
"hanser"
127.0.0.1:6379> getrange name 0 -1
"hanser"
127.0.0.1:6379> getrange name 0 4
"hanse"
127.0.0.1:6379> getrange name -3 -1
"ser"
127.0.0.1:6379> getrange name -3 10086
"ser"
127.0.0.1:6379> getrange name -3 -4
""
127.0.0.1:6379> 

我们看到,索引是可以从后往前数,但是只能从前往后、不能从后往前获取。也就是getrange word -1 -3是不可以的,会返回一个空字符串,因为-1在-3的后面。

setrange key start value:从索引为start的地方开始,将key对应的值替换为value,替换的个数等于value的个数。

127.0.0.1:6379> get name
"hanser"
127.0.0.1:6379> setrange name 0 you
(integer) 6  # 从索引为0的地方开始替换,替换三个字符,因为我们指定了3个字符
127.0.0.1:6379> get name
"youser"
127.0.0.1:6379> setrange name 10 you
(integer) 13  # 从索引为10的地方开始替换,但是字符串索引最大为6,因此会使用\x00填充
127.0.0.1:6379> get name
"youser\x00\x00\x00\x00you"
127.0.0.1:6379> setrange myself 3 gagaga
(integer) 9  # 对于不存在的key也是如此
127.0.0.1:6379> get myself
"\x00\x00\x00gagaga"
127.0.0.1:6379> set name hanser
OK
127.0.0.1:6379> setrange name 0 "han han han han"
(integer) 15  # 替换的字符串长度比相应的key长没有关系,会自动扩充
127.0.0.1:6379> get name
"han han han han"

mset key1 value1 key2 value2:同时设置多个key value

这是一个原子性操作,要么都设置成功,要么都设置不成功。注意:这些都是会覆盖原来的值的,如果不想这样的话,可以使用msetnx,这个命令只会在所有的key都不存在的时候才会设置。

mget key1 key2:同时返回多个key对应的value

如果有的key不存在,那么返回nil。

127.0.0.1:6379> get name
"han han han han"
127.0.0.1:6379> mset name hanser age 28
OK
127.0.0.1:6379> mget name age
1) "hanser"
2) "28"
127.0.0.1:6379> 

getset key value:先返回key的旧值,然后设置新值

127.0.0.1:6379> getset name yousa
"hanser"
127.0.0.1:6379> get name
"yousa"
127.0.0.1:6379> getset ping pong
(nil)
127.0.0.1:6379> get ping
"pong"
127.0.0.1:6379> 

如果有的key不存在,那么返回nil,然后设置。

另外,Redis中还有很多关于key的操作,有必要提前说一下。

keys pattern:查看名称满足pattern所有的key,像string、list、hash、set、zset都有自己的key,key不可以重名,比如有一个叫name的string,那么就不可以再有一个还叫name的。

127.0.0.1:6379> keys *  # 查看所有的key
 1) "gender"
 2) "word"
 3) "ping"
 4) "name"
 5) "age2"
 6) "age1"
 7) "age"
 8) "myself"
 9) "age3"
10) "age4"
127.0.0.1:6379> keys *a*  # 查看包含a的key
1) "name"
2) "age2"
3) "age1"
4) "age"
5) "age3"
6) "age4"
127.0.0.1:6379> keys age?  # 查看以age开头、总共4个字符的key
1) "age2"
2) "age1"
3) "age3"
4) "age4"

exists key:判断某个key是否存在

127.0.0.1:6379> exists name
(integer) 1
127.0.0.1:6379> exists name1
(integer) 0  # 存在返回1,不存在返回0
127.0.0.1:6379> exists name name1
(integer) 1  # 也可以指定多个key,返回存在的key的个数,但是此时无法判断到底是哪个key存在

ttl key:查看还有多少秒过期,-1表示永不过期,-2表示已过期

127.0.0.1:6379> ttl name
(integer) -1  # -1表示永不过期
127.0.0.1:6379> ttl name1
(integer) -2  # -2表示已经过期
127.0.0.1:6379> 

key是可以设置过期时间的,如果过期了就不能再用了。我们看到name1这个key压根就不存在,返回的也是-2,因为过期了就相当于不存在了。而name是-1,表示永不过期

expire key 秒钟:为给定的key设置过期时间

127.0.0.1:6379> expire name 60
(integer) 1  # 设置60s,设置成功返回1
127.0.0.1:6379> ttl name
(integer) 55  # 查看时间,还剩下55秒
127.0.0.1:6379> expire name1 60
(integer) 0  # name1不存在,设置失败,返回0
127.0.0.1:6379> 

这里设置60s的过期时间。另外设置完之后,在过期时间结束之前是可以再次设置的,比如我先设置了60s,然后快结束的时候我再次设置60s,那么还会再持续60s。

type key:查看你的key是什么类型

127.0.0.1:6379> type name
none  # name过期了,相当于不存在了,因此为none
127.0.0.1:6379> type age
string  # 类型为string
127.0.0.1:6379>

move key db:将key移动到指定的db中

127.0.0.1:6379> flushdb
OK  # 清空当前库,如果是清空所有库,可以使用flushall,当然后面都可以加上async,表示异步删除,我们前面说过的
127.0.0.1:6379> set name hanser
OK
127.0.0.1:6379> keys *
1) "name"
127.0.0.1:6379> move name 3
(integer) 1  # 将name移动到索引为3的库中
127.0.0.1:6379> keys *
(empty array)  # 此时当前库已经没有name了
127.0.0.1:6379> select 3
OK  # 切换到索引为3的库中
127.0.0.1:6379[3]> keys *
1) "name"  # keys *查看,发现name已经有了
127.0.0.1:6379[3]> select 0  # 切换回来
OK
127.0.0.1:6379> 

然后我们来看看如何使用Python来操作Redis,这里操作字符串

笔者是Python系的,所以如果你不搞Python的话,那么可以不用看。

import redis

# 获取得到的默认是字节,如果指定了decode_responses,会自动进行解码
client = redis.Redis(host="47.94.174.89", decode_responses="utf-8")

# 1. set key value
client.set("name", "yousa", ex=None, px=None, nx=False, xx=False)

# 2. get key
print(client.get("name"), client.get("age"))  # yousa None

# 3. del key1 key2 ...
print(client.delete("name", "age"))  # 1

# 4. apend key value
client.set("name", "han")
print(client.append("name", "ser"))  # 6
print(client.get("name"))  # hanser

# 5. strlen key
print(client.strlen("name"))  # 6

# 6. incr key
client.set("age", 28)
# incr key其实等价于incrby key 1,因此在这里两个命令都是通过incr实现
# 第二个参数为1,是默认值,当然我们也可以自己指定
client.incr("age", 1)
print(client.get("age"))  # 29

# 7. decr key
client.decr("age", 10)
print(client.get("age"))  # 19

# 8. getrange key start end
print(client.getrange("name", -3, -1))  # ser

# 9. setrange key start value
client.setrange("name", 3, "sa")
print(client.get("name"))  # hansar

# 10. mset key1 value1 key2 value2
client.mset({"name": "yousa", "age": 20})

# 11. mget key1 key2
print(client.mget(["name", "age", "gender"]))  # [‘yousa‘, ‘20‘, None]

# 12. getset key value
print(client.getset("name", "hanser"))  # yousa
print(client.get("name"))  # hanser

# 13. keys pattern
print(client.keys("*"))  # [‘name‘, ‘age‘]

# 14. exists key
print(client.exists("name"), client.exists("ping"))  # 1 0

# 15. ttl key
print(client.ttl("name"))  # -1

# 16. expire key 秒钟
client.expire("name", 60) 
import time; time.sleep(2)
print(client.ttl("name"))  # 58

# 17. type key
print(client.type("name"))  # string

# 18. move key db
client.move("name", 15)
print(client.get("name"))  # None
# 需要重新连接
print(redis.Redis(host="47.94.174.89", decode_responses="utf-8", db=15).get("name"))  # hanser

我们看到,和Redis命令之间是几乎没有什么区别的。

字符串这种数据结构可以用在什么地方呢?

我们讨论完字符串的相关操作,那么我们还要理解字符串要用在什么地方。

首先字符串类型的使用场景有很多,但从功能的角度来区分,大致可分为以下两种:

  • 1. 字符串存储和操作;
  • 2. 整数类型和浮点类型的存储和计算。

其最常用的业务场景大致分为以下几个。

1. 页面数据缓存

我们知道,一个系统最宝贵的资源就是数据库资源,随着公司业务的发展壮大,数据库的存储量也会越来越大,并且要处理的请求也越来越多,当数据量和并发量到达一定级别之后,数据库就变成了拖慢系统运行的“罪魁祸首”,为了避免这种情况的发生,我们可以把查询结果放入缓存(Redis)中,让下次同样的查询直接去缓存系统取结果,而非查询数据库,这样既减少了数据库的压力,同时也提高了程序的运行速度。

画一张图来说明一下:

技术图片

2. 数据计算与统计

Redis 可以用来存储整数和浮点类型的数据,并且可以通过命令直接累加并存储整数信息,这样就省去了每次先要取数据、转换数据、拼加数据、再存入数据的麻烦,只需要使用一个命令就可以完成此流程。比如:微博、哔哩哔哩等社交平台,我们经常会点赞,然后还有点赞数。每点一个赞,点赞数就加1,这个功能就完全可以交给Redis实现。

3. 共享Session信息

通常我们在开发后台管理系统时,会使用 Session 来保存用户的会话(登录)状态,这些 Session 信息会被保存在服务器端,但这只适用于单系统应用,如果是分布式系统此模式将不再适用。

例如用户A的 Session 信息被存储在第一台服务器,但第二次访问时用户A被分配到第二台服务器,这个时候服务器并没有用户A的 Session 信息,就会出现需要重复登录的问题。分布式系统每次会把请求随机分配到不同的服务器,因此我们需要借助缓存系统对这些 Session 信息进行统一的存储和管理,这样无论请求发送到哪台服务器,服务器都会去统一的缓存系统获取相关的 Session 信息,这样就解决了分布式系统下 Session 存储的问题。

  • 分布式系统单独存储Session

技术图片

  • 分布式系统使用统一的缓存系统存储Session

技术图片

Redis列表(List)

3. Redis有哪些数据类型?

标签:存储结构   是什么   登录   提高   存在   python   port   com   get   

原文地址:https://www.cnblogs.com/traditional/p/13279038.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!