Redis-常用数据类型
2022-07-18
Redis-常用数据类型
查看redis常见数据类型操作命令: http://www.redis.cn/commands.html
key类型
[commands] # 这些命令的含义很容易看出,故直接看例子吧
- keys *
- set key value
- exists key
- type key
- del key
- unlink key
- expire key time(second)
- ttl key
- dbsize
[cindy@iZbp15qc4wmx335c268l5mZ ~]$ redis-cli
127.0.0.1:6379> keys * # 列出当前数据库的所有key
(empty array)
127.0.0.1:6379> set k1 cindy # 设置key为"k1"的值为"cindy"
OK
127.0.0.1:6379> set k2 coco
OK
127.0.0.1:6379> set k3 alice
OK
127.0.0.1:6379> keys *
1) "k3"
2) "k1"
3) "k2"
127.0.0.1:6379> exists k1 # 是否存在k1,结果用(integer) 1/0表示
(integer) 1
127.0.0.1:6379> exists k4
(integer) 0
127.0.0.1:6379> type k1 # 查看key的类型
string
127.0.0.1:6379> del k1 # 删除key方法一
(integer) 1
127.0.0.1:6379> unlink k2 # 删除key方法二(根据value选择非阻塞删除,仅将keys从keyspace元数据中删除,真正的删除会在后续异步操作)
(integer) 1
127.0.0.1:6379> keys *
1) "k3"
127.0.0.1:6379> expire k4 10 # 设置已有key的过期时间(单位秒)
(integer) 0 # 由于k4不是已有的key,所以返回是0
127.0.0.1:6379> expire k3 10
(integer) 1
127.0.0.1:6379> ttl k3 # 查看key的过期时间(特殊:-1表示永不过期,-2表示已过期)
(integer) 7
127.0.0.1:6379> ttl k3
(integer) -2
127.0.0.1:6379> set k5 xxx
OK
127.0.0.1:6379> ttl k5
(integer) -1
127.0.0.1:6379> dbsize # 当前数据库的key总数
(integer) 1
127.0.0.1:6379>
flushdb # 清空当前库
flushall # 通杀全部库
String类型
- 是Redis中value最基本的类型
- 是二进制安全的,意味着Redis的string可以包含任何数据,比如jpg图片或者序列化的对象
- Redis中字符串value最多512M
- String的数据结构为简单动态字符串(Simple Dynamic String,缩写SDS)。内部结构实现上类似于Java的ArrayList,采用预分配冗余空间的方式来减少内存的频繁分配,在需要时扩容。
基本操作
[commands] # 这些命令的含义很容易看出,故直接看例子吧
- set key value
- setnx key value # 设置key-value值(仅当key不存在时才设置成功)
- get key
- append key value
- strlen key
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> set k1 value1 # 设置key-value值
OK
127.0.0.1:6379> get k1 # 获取key对应的值
"value1"
127.0.0.1:6379> append k1 abd # 在key值后面追加
(integer) 9 # 返回追加后的value长度
127.0.0.1:6379> get k1
"value1abd"
127.0.0.1:6379> strlen k1 # key长度
(integer) 9
127.0.0.1:6379> setnx k1 abc # 设置key-value值(仅当key不存在时才设置成功)
(integer) 0
127.0.0.1:6379> get k1
"value1abd"
127.0.0.1:6379> setnx k2 abc
(integer) 1
127.0.0.1:6379> get k2
"abc"
127.0.0.1:6379> set k2 def # 对于已存在的key,set设置直接覆盖
OK
127.0.0.1:6379> get k2
"def"
对值为数字的增减操作
[commands] # 这些命令的含义很容易看出,故直接看例子吧
- incr key
- decr key
- incrby key len
- decrby key len
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> set k1 100 # 需要设置value为数字
OK
127.0.0.1:6379> incr k1 # 设置key对应的value自增1
(integer) 101
127.0.0.1:6379> decr k1 # 设置key对应的value自减1
(integer) 100
127.0.0.1:6379> incrby k1 3 # 指定步长的自增
(integer) 103
127.0.0.1:6379> decrby k1 4 # 指定步长的自减
(integer) 99
值得注意的是,redis的增减操作具有原子性。
所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch (切换到另一个线程)。
(1)在单线程中, 能够在单条指令中完成的操作都可以认为是"原子操作",因为中断只能发生于指令之间。
(2)在多线程中,不能被其它进程(线程)打断的操作就叫原子操作。
Redis单命令的原子性主要得益于Redis的单线程。
例如java的i++就不是单线程。
批量操作
[commands] # 这些命令的含义很容易看出,故直接看例子吧
- mset key1 value1 key2 value2 ...
- msetnx key1 value1 key2 value2 ...
- mget key1 key2 ...
127.0.0.1:6379> mset k1 v1 k2 v2 # 批量设置多个key-value
OK
127.0.0.1:6379> keys *
1) "k1"
2) "k2"
127.0.0.1:6379> mget k1 k2 # 批量获取多个key的value值
1) "v1"
2) "v2"
127.0.0.1:6379> msetnx k1 v11 k3 v3 # 批量设置多个key-value(但是判断是否已存在,若其中有一个已存在,则整体设置失败) -> 原子性
(integer) 0
127.0.0.1:6379> keys * # 设置失败,故keys不变
1) "k1"
2) "k2"
127.0.0.1:6379> msetnx k3 v3 k4 v4
(integer) 1
127.0.0.1:6379> keys * # 设置成功
1) "k4"
2) "k3"
3) "k1"
4) "k2"
范围和过期时间设置
[commands]
- getrange key beginIndex endINdex # 类似substring,取一定区间的子字符串(且begin和end的字符都要),索引从0开始
- setrange key beginIndex value # 从beginIndex开始覆盖
- setex key expireTime value # 新建key并设置过期时间(秒)
- getset key value # 设置key的新值,并输出其旧值
127.0.0.1:6379> set key1 cindy
OK
127.0.0.1:6379> getrange key1 1 3 # 索引从0开始
"ind"
127.0.0.1:6379> setrange key1 1 aa
(integer) 5 # 输出覆盖完成后的字符串长度
127.0.0.1:6379> get key1
"caady"
127.0.0.1:6379> setex key2 10 value2
OK
127.0.0.1:6379> ttl key2
(integer) 6
127.0.0.1:6379> ttl key2
(integer) -2
127.0.0.1:6379> keys * # key2已过期,不存在了
1) "key1"
127.0.0.1:6379> getset key1 panda
"caady" # 输出旧值
127.0.0.1:6379> get key1
"panda" # 输出新值
List类型
-
单键多值
-
字符串列表,按插入顺序排序,可从队头或尾插入
-
底层是双向链表,故两边操作比中间操作代价小得多
-
数据结构是快速链表quickList,由多个压缩链表ziplist双向链接而成(压缩链表是一块连续的内存存储,它将所有的元素紧挨着一起存储)。这样既满足了快速的插入删除性能,又不会出现太大的空间冗余(不需要很多左右指针)。
基本操作
[commands]
- lpush/rpush list value1 value2 ... # 从左/右边插入1或多个value
- lpop/rpop list # 从左/右边弹出1个value
- rpoplpush list1 list2 # 从list1列表右边弹出一个值插入到list2的左边
- lrange list left right # 输出index为[left,right]的子列表(index从0开始)
lrange list 0 -1 # 特别地,取出所有值
- lindex list index # 取出给定下标的元素(从左边数)
- llen list # 获取列表长度
- linsert list before/after value new_value # 从值为value的节点前面/后面插入new_value
- lrem list num value # 将列表从左开始删除num个值为value的节点
- lset list index value # 将下标index的值设为value
127.0.0.1:6379> rpush l1 v1 v2 v3
(integer) 3
127.0.0.1:6379> lrange l1 0 -1
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> lpush l2 v11 v22 v33
(integer) 3
127.0.0.1:6379> lrange l2 0 -1
1) "v33"
2) "v22"
3) "v11"
127.0.0.1:6379> lpop l1
"v1" # 输出弹出的value
127.0.0.1:6379> lrange l1 0 -1
1) "v2"
2) "v3"
127.0.0.1:6379> rpop l2
"v11"
127.0.0.1:6379> lrange l2 0 -1
1) "v33"
2) "v22"
127.0.0.1:6379> rpoplpush l1 l2
"v3" # l1弹出的值
127.0.0.1:6379> lrange l1 0 -1
1) "v2"
127.0.0.1:6379> lrange l2 0 -1 # v3成功从左边插入到l2
1) "v3"
2) "v33"
3) "v22"
127.0.0.1:6379> lindex l2 1
"v33"
127.0.0.1:6379> llen l2
(integer) 3
127.0.0.1:6379> linsert l2 after v3 v3_after
(integer) 4
127.0.0.1:6379> lrange l2 0 -1
1) "v3"
2) "v3_after"
3) "v33"
4) "v22"
127.0.0.1:6379> linsert l2 before v3_after v3
(integer) 5
127.0.0.1:6379> lrange l2 0 -1
1) "v3"
2) "v3"
3) "v3_after"
4) "v33"
5) "v22"
127.0.0.1:6379> lrem l2 2 v3 # 从左开始删除2个v3
(integer) 2
127.0.0.1:6379> lrange l2 0 -1
1) "v3_after"
2) "v33"
3) "v22"
127.0.0.1:6379> lset l2 1 v33_new
OK
127.0.0.1:6379> lrange l2 0 -1
1) "v3_after"
2) "v33_new"
3) "v22"
Set类型
- 无序,不重复
- 底层是一个value为null的hash表,所以添加,删除,查找的复杂度都是O(1)
- Set数据结构是dict字典,字典是用哈希表实现的。Java中HashSet的内部实现使用的是HashMap,只不过所有的value都指向同一个对象。Redis的set结构也是一样,它的内部也使用hash结构,所有的value都指向同一个内部值。
基本操作
[commands]
- sadd set value1 value2 ... # 插入集合值(已存在值会被忽略)
- smembers set # 输出集合的所有值
- sismember set value # 判断value是否在set中
- scard set # 获取set所含元素个数
- srem set value1 value2 ... # 删除元素
- spop set # 随机弹出set的一个值
- srandmember set num # 随机获取num个值,但不会删除
- smove set1 set2 value # 将value从set1转移到set2
- sinter set1 set2 # 取交集
- sunion set1 set2 # 取并集
- sdiff set1 set2 # 取差集
127.0.0.1:6379> sadd s1 v1 v2
(integer) 2
127.0.0.1:6379> smembers s1
1) "v1"
2) "v2"
127.0.0.1:6379> sismember s1 v2
(integer) 1
127.0.0.1:6379> sismember s1 v3
(integer) 0 # 存在-1;不存在-0
127.0.0.1:6379> scard s1
(integer) 2
127.0.0.1:6379> srem s1 v1
(integer) 1
127.0.0.1:6379> smembers s1
1) "v2"
127.0.0.1:6379> sadd s2 v1 v2 v3
(integer) 3
127.0.0.1:6379> srandmember s2
"v3"
127.0.0.1:6379> srandmember s2
"v1"
127.0.0.1:6379> smove s2 s1 v3
(integer) 1
127.0.0.1:6379> smembers s1
1) "v2"
2) "v3"
127.0.0.1:6379> smembers s2
1) "v1"
2) "v2"
127.0.0.1:6379> sinter s1 s2
1) "v2"
127.0.0.1:6379> sunion s1 s2
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> sdiff s1 s2
1) "v3"
Hash类型
- 键值对集合,field-value映射
- 类似java的Map
- Hash类型对应的数据结构是两种:ziplist(压缩列表),hashtable(哈希表)。当field-value长度较短且个数较少时,使用ziplist,否则使用hashtable。
基本操作
[commands]
- hset key field1 value1 field2 value2 # 赋值
- hget key field # 取值
- hexists key field # 查看field是否存在
- hkeys key # 列出key的所有fields
- hvals key # 列出key的所有values
- hincrby key field increment # 为数值域加上增量
- hsetnx key field value # 仅当当前field不存在,才设置值
127.0.0.1:6379> hset user1 id 001 name cindy age 100
(integer) 3
127.0.0.1:6379> hget user1 id
"001"
127.0.0.1:6379> hget user1 sex
(nil) # 无此field
127.0.0.1:6379> hkeys user1
1) "id"
2) "name"
3) "age"
127.0.0.1:6379> hvals user1
1) "001"
2) "cindy"
3) "100"
127.0.0.1:6379> hincrby user1 age 2
(integer) 102
127.0.0.1:6379> hvals user1
1) "001"
2) "cindy"
3) "102" # 100+2
127.0.0.1:6379> hsetnx user1 age 200
(integer) 0 # 由于已有age键,故设置失败
127.0.0.1:6379> hvals user1
1) "001"
2) "cindy"
3) "102"
127.0.0.1:6379> hsetnx user1 sex female
(integer) 1
127.0.0.1:6379> hkeys user1
1) "id"
2) "name"
3) "age"
4) "sex" # 新增成功
127.0.0.1:6379> hvals user1
1) "001"
2) "cindy"
3) "102"
4) "female"
Zset类型
-
是一种有序的set类型,通过每个value的score字段排序(由低到高排序)
-
值是唯一的,但score是可重复的
-
方便访问一个score范围内的值,访问中间的元素也快
-
底层数据结构:Hash(关联元素value和权重score,保障元素value的唯一性,可以通过元素value找到相应的score值)+跳跃表(给元素value排序,根据score的范围获取元素列表)
跳表:
基本操作
[commands]
- zadd key score1 value1 score2 value2 ... # 赋值(加上socre)
- zrange key begin end [withscores] # 返回一定下标范围的值,WITHSCORES加上的话可额外显示score
- zrangebyscore key min max [withscores] [limit offset count] # 指定返回的score范围的value,其中offset和count分别可指定偏移量和个数
- zrevrangebyscore key max min [withscores] [limit offset count] # 反向排序输出
- zincrby key increment value # 为元素的score加上增量
- zrem key value # 删除元素
- zcount key min max # 统计指定score范围内的元素个数
- zrank key value # 返回元素在集合key中的排名(从0开始)
127.0.0.1:6379> zadd key1 1 v1 2 v2
(integer) 2
127.0.0.1:6379> zrange key1 0 1 # 按socre从到大排列显示[0,1]下标内的值
1) "v1"
2) "v2"
127.0.0.1:6379> zrange key1 0 1 withscores # 相应score显示在下面
1) "v1"
2) "1"
3) "v2"
4) "2"
127.0.0.1:6379> zadd key1 3 v3
(integer) 1
127.0.0.1:6379> zrangebyscore key1 1 2 # 取socre范围[1,2]的值
1) "v1"
2) "v2"
127.0.0.1:6379> zrangebyscore key1 1 3 limit 1 1 # 结果偏移量为1,且仅选取一个值,即为v2
1) "v2"
127.0.0.1:6379> zrevrangebyscore key1 3 2 withscores # 反向顺序
1) "v3"
2) "3"
3) "v2"
4) "2"
127.0.0.1:6379> zincrby key1 5 v3
"8" # 输出加后的score
127.0.0.1:6379> zrem key1 v1
(integer) 1
127.0.0.1:6379> zrange key1 0 -1 withscores # 取出全部看下
1) "v2"
2) "2"
3) "v3"
4) "8"
127.0.0.1:6379> zcount key1 3 8
(integer) 1
127.0.0.1:6379> zcount key1 1 9
(integer) 2
127.0.0.1:6379> zrank key1 v2 # 排名下标从0开始
(integer) 0