Redis
redis
的安装
linux
下的环境准备
yum install centos-release-scl scl-utils-build
yum install -y devtoolset-8-toolchain
scl enable devtoolset-8 bash
gcc --version
# 下载redis-6.2.1.tar.gz放/opt目录
# tar -zxvf redis-6.2.1.tar.gz
# cd redis-6.2.1
# make
# make install
# 安装目录 /usr/local/bin
# 启动
redis-server /myredis/redis.conf
# 重启
ps -ef | grep redis
kill -9 port
/usr/local/bin/redis-server /usr/local/bin/myredis/redis.conf
redis
中键值对的操作
keys *
查看当前库中所有的key
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379>
exists key
判断某个key
是否存在
127.0.0.1:6379> exists k1
(integer) 1
127.0.0.1:6379>
type key
查看你的key
是什么类型
127.0.0.1:6379> type k1
string
del key
删除指定的key
数据
127.0.0.1:6379> del k1
(integer) 1
unlink key
根据value
选择非阻塞删除,仅将keys
从keyspace
元数据中删除,真正的删除会在后续异步操作。
127.0.0.1:6379> set k2 lhq
OK
127.0.0.1:6379> unlink k2
(integer) 1
expire key 10
10秒钟:为给定的key
设置过期时间
127.0.0.1:6379> set k1 llj
OK
127.0.0.1:6379> expire k1 10
(integer) 1
ttl key
查看还有多少秒过期,-1表示永不过期,-2表示已过期
127.0.0.1:6379> set k1 ljq
OK
127.0.0.1:6379> ttl k1
(integer) -1
127.0.0.1:6379> expire k1 10
(integer) 1
127.0.0.1:6379> ttl k1
(integer) 7
127.0.0.1:6379> ttl k1
(integer) -2
select
命令切换数据库
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]>
dbsize
查看当前数据库的key
的数量
127.0.0.1:6379> dbsize
(integer) 0
flushdb
清空当前库 慎重使用
flushall
通杀全部库 慎重使用
redis
中的五大数据类型
String
类型
String
是Redis
最基本的类型,你可以理解成与Memcached
一模一样的类型,一个key
对应一个value
。String
类型是二进制安全的。意味着Redis
的string
可以包含任何数据。比如jpg
图片或者序列化的对象。String
类型是Redis
最基本的数据类型,一个Redis
中字符串value
最多可以是512M
常用命令:
set key value
添加键值对,如果key
已经存在,则是覆盖操作
get key
获取对应key
的value
127.0.0.1:6379> set k1 100
OK
127.0.0.1:6379> get k1
"100"
参数说明:
NX
:当数据库中key
不存在时,可以将key-value
添加数据库
EX:key
的超时秒数
PX:key
的超时毫秒数,与EX
互斥
append key value
将给定的value
追加到原值的末尾,返回值是string
类型的长度
127.0.0.1:6379> get k1
"100"
127.0.0.1:6379> append k1 abc
(integer) 6
127.0.0.1:6379> get k1
"100abc"
strlen key
获得值的长度
127.0.0.1:6379> strlen k1
(integer) 6
setnx key value
只有在 key
不存在时 设置 key
的值,如果存在了,则不能设置
127.0.0.1:6379> keys *
1) "k1"
127.0.0.1:6379> get k1
"100abc"
127.0.0.1:6379> setnx k1 123
(integer) 0
127.0.0.1:6379> get k1
"100abc"
127.0.0.1:6379> setnx k2 123
(integer) 1
127.0.0.1:6379> keys *
1) "k2"
2) "k1"
127.0.0.1:6379> get k2
"123"
incr key
将 key
中储存的数字值增1,只能对数字值操作,如果为空,新增值为1。返回值为结果
127.0.0.1:6379> set k2 0
OK
127.0.0.1:6379> incr k2
(integer) 1
127.0.0.1:6379> get k2
"1"
decr key
将 key
中储存的数字值减1,只能对数字值操作,如果为空,新增值为-1。返回值为结果
127.0.0.1:6379> decr k2
(integer) 0
127.0.0.1:6379> get k2
"0"
incrby / decrby key numValue
将 key
中储存的数字值增减。自定义步长numValue
。返回值为结果
127.0.0.1:6379> incrby k2 10
(integer) 10
127.0.0.1:6379> get k2
"10"
127.0.0.1:6379> decrby k2 10
(integer) 0
补充:关于redis
的原子性
所谓原子操作是指不会被线程调度机制打断的操作;
这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch
(切换到另一个线程)。
- 在单线程中, 能够在单条指令中完成的操作都可以认为是"原子操作",因为中断只能发生于指令之间。
- 在多线程中,不能被其它进程(线程)打断的操作就叫原子操作。
Redis
单命令的原子性主要得益于Redis
的单线程。
mset key1 value1 key2 value2 key3 value3 .....
设置多个键值对
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3
OK
127.0.0.1:6379> keys *
1) "k2"
2) "k1"
3) "k3"
mget key1 key2 key3.....
同时获取一个或多个 value
127.0.0.1:6379> mget k1 k2 k3
1) "v1"
2) "v2"
3) "v3"
msetnx key1 value1 key2 value2 key3 value3 .....
同时设置一个或多个 key-value
对,当且仅当所有给定 key
都不存在。
多个操作中有一个操作不成功,则全部失败
127.0.0.1:6379> msetnx k11 v11 k22 v22 k3 v33
(integer) 0
127.0.0.1:6379> msetnx k11 v11 k22 v22 k33 v33
(integer) 1
getrange key startIndex endIndex
获得值的范围,类似java
中的substring
127.0.0.1:6379> set name lucymary
OK
127.0.0.1:6379> getrange name 0 3
"lucy"
setrange key startIndex value
用 value
覆写key
所储存的字符串值,从起始位置startIndex
开始(索引从0开始)。
127.0.0.1:6379> setrange name 3 abc
(integer) 8
127.0.0.1:6379> get name
"lucabcry"
setex key expireTime value
设置键值的同时,设置过期时间,单位秒。
127.0.0.1:6379> setex k234 10 123
OK
127.0.0.1:6379> ttl k234
(integer) 7
127.0.0.1:6379> ttl k234
(integer) 3
getset key value
以新换旧,设置了新值同时获得旧值。
127.0.0.1:6379> getset name jack
"lucabcry"
127.0.0.1:6379> get name
"jack"
String
类型的数据结构
String
的数据结构为简单动态字符串(Simple Dynamic String
,缩写SDS
)。是可以修改的字符串,内部结构实现上类似于Java
的ArrayList
,采用预分配冗余空间的方式来减少内存的频繁分配.
当前字符串实际分配的空间capacity
一般要高于实际字符串长度len
。当字符串长度小于1M
时,扩容都是加倍现有的空间,如果超过1M
,扩容时一次只会多扩1M
的空间。需要注意的是字符串最大长度为512M
。
List
类型
单键多值,Redis
列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。
它的底层实际是个双向链表,对两端的操作性能很高,通过索引下标的操作中间的节点性能会较差。
lpush key value1 value2 value3....
从左边插入一个或多个值。每次插入的都是在当前链表中的左边插入,即编写顺序为
v1 v2 v3
实际存储为 v3 v2 v1
127.0.0.1:6379> lpush k1 v1 v2 v3
(integer) 3
127.0.0.1:6379> lrange k1 0 -1 # 后面会介绍
1) "v3"
2) "v2"
3) "v1"
rpush key value1 value2 value3....
从右边插入一个或多个值。每次插入的都是在当前链表中的右边插入,即编写顺序为
v11 v22 v33
实际存储为 v11 v22 v33
127.0.0.1:6379> rpush k2 v11 v22 v33
(integer) 3
127.0.0.1:6379> lrange k2 0 -1
1) "v11"
2) "v22"
3) "v33"
lpop key
从左边/右边吐出一个值。**值在键在,值光键亡。**当键里面的list
为空的时候,这个键就消失了
127.0.0.1:6379> keys *
1) "k2"
2) "k1"
127.0.0.1:6379> lpop k1
"v3"
127.0.0.1:6379> lpop k1
"v2"
127.0.0.1:6379> lpop k1
"v1"
127.0.0.1:6379> keys *
1) "k2"
rpop key
从右边吐出一个值。**值在键在,值光键亡。**当键里面的list
为空的时候,这个键就消失了
127.0.0.1:6379> keys *
1) "k2"
127.0.0.1:6379> rpop k2
"v33"
127.0.0.1:6379> rpop k2
"v22"
127.0.0.1:6379> rpop k2
"v11"
127.0.0.1:6379> keys *
rpoplpush key1 key2
从key1
列表右边吐出一个值,插到key2
列表左边。
127.0.0.1:6379> lrange k1 0 -1
1) "v3"
2) "v2"
3) "v1"
127.0.0.1:6379> lrange k2 0 -1
1) "v11"
2) "v22"
3) "v33"
127.0.0.1:6379> rpoplpush k1 k2
"v1"
127.0.0.1:6379> lrange k2 0 -1
1) "v1"
2) "v11"
3) "v22"
4) "v33"
lrange key LIndex RIndex
按照索引下标获得元素(从左到右)
lrange key1 0 -1
0左边第一个,-1右边第一个,(0-1表示获取所有)
127.0.0.1:6379> lrange k2 0 -1
1) "v1"
2) "v11"
3) "v22"
4) "v33"
lindex key index
按照索引下标获得元素(从左到右)
127.0.0.1:6379> lrange k2 0 -1
1) "v1"
2) "v11"
3) "v22"
4) "v33"
127.0.0.1:6379> lindex k2 3
"v33"
llen key
获得列表长度
127.0.0.1:6379> llen k2
(integer) 4
linsert key before value newValue
在value
的前面插入newValue
插入值
linsert key after value newValue
在value
的后面插入newValue
插入值
127.0.0.1:6379> linsert k1 before v2 newv2
(integer) 3
127.0.0.1:6379> lrange k1 0 -1
1) "v3"
2) "newv2"
3) "v2"
127.0.0.1:6379> linsert k1 after v2 newafterv2
(integer) 4
127.0.0.1:6379> lrange k1 0 -1
1) "v3"
2) "newv2"
3) "v2"
4) "newafterv2"
lrem key n value
从左边删除n
个value
(从左到右),匹配n
个与value
相同的,n
为最大个相同的值
127.0.0.1:6379> lpush k2 v22 v23 v22
(integer) 5
127.0.0.1:6379> lrange k2 0 -1
1) "v22"
2) "v23"
3) "v22"
4) "v11"
5) "v22"
127.0.0.1:6379> lrem k2 2 "v22"
(integer) 2
127.0.0.1:6379> lrange k2 0 -1
1) "v23"
2) "v11"
3) "v22"
lset key index value
将列表key
下标为index
的值替换成value
127.0.0.1:6379> lset k2 0 v123123
OK
127.0.0.1:6379> lrange k2 0 -1
1) "v123123"
2) "v11"
3) "v22"
补充:List
的数据结构为快速链表quickList
。
首先在列表元素较少的情况下会使用一块连续的内存存储,这个结构是ziplist
,也即是压缩列表。
它将所有的元素紧挨着一起存储,分配的是一块连续的内存。
当数据量比较多的时候才会改成quicklist
。
因为普通的链表需要的附加指针空间太大,会比较浪费空间。比如这个列表里存的只是int类型的数据,结构上还需要两个额外的指针prev
和next
。
Redis
将链表和ziplist
结合起来组成了quicklist
。也就是将多个ziplist
使用双向指针串起来使用。这样既满足了快速的插入删除性能,又不会出现太大的空间冗余。
Set
类型
Redis set
对外提供的功能与list
类似是一个列表的功能,特殊之处在于set
是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set
是一个很好的选择,并且set
提供了判断某个成员是否在一个set
集合内的重要接口,这个也是list
所不能提供的。
Redis
的Set
是string
类型的无序集合。它底层其实是一个value
为null
的hash
表,所以添加,删除,查找的复杂度都是O(1)。
一个算法,随着数据的增加,执行时间的长短,如果是O(1)
,数据增加,查找数据的时间不变
sadd key value1 value2 value3 .....
将一个或多个 member 元素加入到集合 key 中,已经存在的 member 元素将被忽略
smembers key
取出该集合的所有值。
127.0.0.1:6379> sadd k1 v1 v2 v3
(integer) 3
127.0.0.1:6379> sadd k1 v3 v4 v5
(integer) 2
127.0.0.1:6379> get k1
127.0.0.1:6379> smembers k1
1) "v3"
2) "v2"
3) "v4"
4) "v1"
5) "v5"
sismember key value
判断集合key
是否为含有该value
值,有1,没有0
127.0.0.1:6379> smembers k1
1) "v3"
2) "v2"
3) "v4"
4) "v1"
5) "v5"
127.0.0.1:6379> sismember k1 v1
(integer) 1
127.0.0.1:6379> sismember k1 v11
(integer) 0
scard key
返回该集合的元素个数。
127.0.0.1:6379> scard k1
(integer) 5
srem key value1 value2 ....
删除集合中的某个元素。返回值未删除个数,没找找到value
则返回0
127.0.0.1:6379> srem k1 v11
(integer) 0
127.0.0.1:6379> srem k1 v1
(integer) 1
127.0.0.1:6379> srem k1 v2 v5
(integer) 2
127.0.0.1:6379> smembers k1
1) "v3"
2) "v4"
spop key
随机从该集合中吐出一个值。吐出即移除了
127.0.0.1:6379> spop k1
"v4"
127.0.0.1:6379> spop k1
"v3"
127.0.0.1:6379> smembers k1
(empty array)
srandmember key n
随机从该集合中取出n个值。不会从集合中删除 。
127.0.0.1:6379> srandmember k1 3
1) "v2"
2) "v8"
3) "v4"
127.0.0.1:6379> smembers k1
1) "v6"
2) "v3"
3) "v5"
4) "v2"
5) "v8"
6) "v7"
7) "v1"
8) "v4"
smove source destination value
把集合中一个值从一个集合移动到另一个集合
127.0.0.1:6379> sadd k2 v123
(integer) 1
127.0.0.1:6379> smove k2 k1 v123
(integer) 1
127.0.0.1:6379> smembers k1
1) "v6"
2) "v3"
3) "v5"
4) "v2"
5) "v8"
6) "v7"
7) "v1"
8) "v4"
9) "v123"
sinter key1 key2
返回两个集合的交集元素。
127.0.0.1:6379> sadd k2 v123 v1 v2
(integer) 3
127.0.0.1:6379> sinter k1 k2
1) "v2"
2) "v1"
3) "v123"
sunion key1 key2
返回两个集合的并集元素。
127.0.0.1:6379> sunion k1 k2
1) "v7"
2) "v1"
3) "v4"
4) "v123"
5) "v6"
6) "v3"
7) "v5"
8) "v2"
9) "v8"
sdiff key1 key2
返回两个集合的差集元素(key1
中的,不包含key2
中的)
127.0.0.1:6379> sdiff k1 k2
1) "v8"
2) "v4"
3) "v7"
4) "v6"
5) "v3"
6) "v5"
补充:数据结构
Set
数据结构是dict
字典,字典是用哈希表实现的。
Java
中HashSet
的内部实现使用的是HashMap
,只不过所有的value
都指向同一个对象。Redis
的set
结构也是一样,它的内部也使用hash
结构,所有的value
都指向同一个内部值。
Hash
类型
Redis hash
是一个键值对集合。
Redis hash
是一个string
类型的field
和value
的映射表,hash
特别适合用于存储对象。
类似Java
里面的MapString,Object>
用户ID
为查找的key
,存储的value
用户对象包含姓名,年龄,生日等信息,通过 key
(用户ID
) + field
(属性标签) 就可以操作对应属性数据了,既不需要重复存储数据,也不会带来序列化和并发修改控制的问题
hset key field value
给key
集合中的 field
键赋值value
127.0.0.1:6379> hset k1:1001 name qiao
(integer) 1
127.0.0.1:6379> hset k1:1001 age 25
(integer) 1
127.0.0.1:6379> hset k1:1001 id 1
(integer) 1
hget key field
从key
集合field
取出 value
127.0.0.1:6379> hget k1:1001 id
"1"
hmset key field1 value1 field1 value1...
批量设置hash
的值
127.0.0.1:6379> hmset k1:1002 id 1002 name zxc age 100
OK
hexists field value
查看哈希表 key
中,给定域 field
是否存在。 1为存在,0为不存在
127.0.0.1:6379> hexists k1:1001 name
(integer) 1
127.0.0.1:6379> hexists k1:1001 name1
(integer) 0
hkeys key
列出该hash
集合的所有field
127.0.0.1:6379> hkeys k1:1002
1) "id"
2) "name"
3) "age"
hvals key
列出该hash
集合的所有value
127.0.0.1:6379> hvals k1:1002
1) "1002"
2) "zxc"
3) "100"
hincrby key field increment
为哈希表 key
中的域 field
的值加上增量 n -n
127.0.0.1:6379> hincrby k1:1002 age 10
(integer) 110
127.0.0.1:6379> hincrby k1:1002 age -10
(integer) 100
hsetnx key field value
将哈希表 key
中的域 field
的值设置为 value
,当且仅当域 field
不存在 . 0失败,1成功
127.0.0.1:6379> hsetnx k1:1001 age 1000
(integer) 0
127.0.0.1:6379> hsetnx k1:1001 age1 1000
(integer) 1
127.0.0.1:6379> hkeys k1:1001
1) "name"
2) "age"
3) "id"
4) "age1"
补充:数据结构
Hash类型对应的数据结构是两种:ziplist
(压缩列表),hashtable
(哈希表)。当field-value
长度较短且个数较少时,使用ziplist
,否则使用hashtable
Zset
类型
Redis
有序集合zset
与普通集合set
非常相似,是一个没有重复元素的字符串集合。
不同之处是有序集合的每个成员都关联了一个评分(score
),这个评分(score
)被用来按照从最低分到最高分的方式排序集合中的成员。集合的成员是唯一的,但是评分可以是重复了 。
因为元素是有序的, 所以你也可以很快的根据评分(score
)或者次序(position
)来获取一个范围的元素。
访问有序集合的中间元素也是非常快的,因此你能够使用有序集合作为一个没有重复成员的智能列表。
zadd key score1 value1 score2 value2 …
将一个或多个 member
元素及其 score
值加入到有序集 key
当中。
127.0.0.1:6379> zadd k1 100 java 200 mysql 300 redis
(integer) 3
zrange key start stop [WITHSCORES]
返回有序集 key 中,下标在start stop
之间的元素,带WITHSCORES
,可以让分数一起和值返回到结果集。0 -1表示全部查出来
127.0.0.1:6379> zrange k1 0 1
1) "java"
2) "mysql"
127.0.0.1:6379> zrange k1 0 -1
1) "java"
2) "mysql"
3) "redis"
127.0.0.1:6379> zrange k1 0 -1 withscores
1) "java"
2) "100"
3) "mysql"
4) "200"
5) "redis"
6) "300"
zrangebyscore key min max [withscores] [limit offset count]
返回有序集 key
中,所有 score
值介于 min
和 max
之间(包括等于 min
或 max
)的成员。有序集成员按 score
值递增(从小到大)次序排列。
127.0.0.1:6379> zrangebyscore k1 100 200
1) "java"
2) "mysql"
127.0.0.1:6379> zrangebyscore k1 100 150
1) "java"
127.0.0.1:6379> zrangebyscore k1 100 300 withscores limit 0 1
1) "java"
2) "100"
127.0.0.1:6379> zrangebyscore k1 100 300 withscores
1) "java"
2) "100"
3) "mysql"
4) "200"
5) "redis"
6) "300"
zrevrangebyscore key max min [withscores] [limit offset count]
同上,改为从大到小排列。
127.0.0.1:6379> zrevrangebyscore k1 200 100
1) "mysql"
2) "java"
127.0.0.1:6379> zrevrangebyscore k1 200 100 withscores
1) "mysql"
2) "200"
3) "java"
4) "100"
127.0.0.1:6379> zrevrangebyscore k1 300 100 withscores limit 0 2
1) "redis"
2) "300"
3) "mysql"
4) "200"
zincrby key increment value
为元素的score
加上增量
127.0.0.1:6379> zincrby k1 10 java
"110"
127.0.0.1:6379> zincrby k1 -10 java
"100"
zrem key value
删除该集合下,指定值的元素
127.0.0.1:6379> zrem k1 java
(integer) 1
127.0.0.1:6379> zrange k1 0 -1
1) "mysql"
2) "redis"
zcount key min max
统计该集合,分数区间内的元素个数
127.0.0.1:6379> zcount k1 100 200
(integer) 1
zrank key value
返回该值在集合中的排名,从0开始。
127.0.0.1:6379> zrange k1 0 -1
1) "java"
2) "tomcat"
3) "mysql"
4) "redis"
127.0.0.1:6379> zrank k1 java
(integer) 0
127.0.0.1:6379> zrank k1 tomcat
(integer) 1
127.0.0.1:6379> zrank k1 redis
(integer) 3
补充:数据结构
SortedSet(zset)
是Redis
提供的一个非常特别的数据结构,一方面它等价于Java
的数据结构Map<String, Double>
,可以给每一个元素value
赋予一个权重score
,另一方面它又类似于TreeSet
,内部的元素会按照权重score
进行排序,可以得到每个元素的名次,还可以通过score
的范围来获取元素的列表。
zset
底层使用了两个数据结构
hash
,hash
的作用就是关联元素value
和权重score
,保障元素value
的唯一性,可以通过元素value
找到相应的score
值。- 跳跃表,跳跃表的目的在于给元素
value
排序,根据score
的范围获取元素列表。