一、Redis的介绍
redis是业界主流的key-value nosql 数据库之一。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。
二、Redis的优点
-
异常快速 : Redis是非常快的,每秒可以执行大约110000设置操作,81000个/每秒的读取操作。
-
支持丰富的数据类型 : Redis支持最大多数开发人员已经知道如列表,集合,可排序集合,哈希等数据类型。这使得在应用中很容易解决的各种问题,因为我们知道哪些问题处理使用哪种数据类型更好解决。
-
操作都是原子的 : 所有 Redis 的操作都是原子,从而确保当两个客户同时访问 Redis 服务器得到的是更新后的值(最新值)。
-
MultiUtility工具:Redis是一个多功能实用工具,可以在很多如:缓存,消息传递队列中使用(Redis原生支持发布/订阅),在应用程序中,如:Web应用程序会话,网站页面点击数等任何短暂的数据
三、Redis API使用
redis-py 的API的使用可以分类为:
- 连接方式
- 连接池
- 操作
- String 操作
- Hash 操作
- List 操作
- Set 操作
- Sort Set 操作
- 管道
- 发布订阅
3.1 连接方式
1. 操作模式
redis-py提供两个类Redis和StrictRedis用于实现Redis的命令,StrictRedis用于实现大部分官方的命令,并使用官方的语法和命令,Redis是StrictRedis的子类,用于向后兼容旧版本的redis-py。
1
2
3
4
5
6
7
8
9
|
import
redis
host
=
'172.16.200.49'
port
=
6379
r
=
redis.Redis(host
=
host, port
=
port)
r.
set
(
'foo'
,
'bar'
)
print
(r.get(
'foo'
))
|
2. 连接池
redis-py使用connection pool来管理对一个redis server的所有连接,避免每次建立、释放连接的开销。默认,每个Redis实例都会维护一个自己的连接池。可以直接建立一个连接池,然后作为参数Redis,这样就可以实现多个Redis实例共享一个连接池。
1
2
3
4
5
6
7
8
9
10
11
|
import
redis
host
=
'172.16.200.49'
port
=
6379
pool
=
redis.ConnectionPool(host
=
host, port
=
port)
r
=
redis.Redis(connection_pool
=
pool)
r.
set
(
'foo'
,
'bar'
)
print
(r.get(
'foo'
))
|
3.1 string操作
redis中的String在在内存中按照一个name对应一个value来存储。如图:
1.set(name, value, ex=None, px=None, nx=False, xx=False)
1
2
3
4
5
6
|
在Redis中设置值,默认,不存在则创建,存在则修改
参数:
ex,过期时间(秒)
px,过期时间(毫秒)
nx,如果设置为
True
,则只有name不存在时,当前
set
操作才执行
xx,如果设置为
True
,则只有name存在时,岗前
set
操作才执行
|
操作命令
1
2
3
4
5
6
7
8
9
10
|
# 设置一个k-v
r.
set
(
'name'
,
'bigberg'
)
print
(r.get(
'name'
))
#设置过期时间为2秒
# 2 秒后获取该值为None
r.
set
(
'name'
,
'bigberg'
, ex
=
2
)
print
(r.get(
'name'
))
time.sleep(
2
)
print
(r.get(
'name'
))
|
2. setnx(name, value)
1
2
3
4
5
6
|
设置值,只有name不存在时,执行设置操作(添加)
如果是r.setnx(
'name'
,
'Tom'
) 则name的值还是
'bigberg'
r.setnx(
'age'
,
22
)
print
(r.get(
'age'
))
|
3. setex(name, value, time)
1
2
3
|
# 设置值
# 参数:
# time,过期时间(数字秒 或 timedelta对象)
|
4. psetex(name, time_ms, value)
1
2
3
|
# 设置值
# 参数:
# time_ms,过期时间(数字毫秒 或 timedelta对象)
|
5. mset(*args, **kwargs)
1
2
3
4
5
6
7
8
|
批量设置值
如:
mset({
'k1'
:
'v1'
,
'k2'
:
'v2'
})
r.mset({
'a'
:
1
,
'b'
:
2
})
print
(r.get(
'a'
))
print
(r.get(
'b'
))
|
6. get(name)
1
|
获取值
|
7. mget(keys, *args)
1
2
3
4
5
6
7
8
9
|
批量获取
如:
mget(
'ylr'
,
'wupeiqi'
)
或
r.mget([
'ylr'
,
'wupeiqi'
])
r.mset({
'a'
:
1
,
'b'
:
2
})
print
(r.mget(
'a'
,
'b'
))
|
8. getset(name, value)
1
2
3
4
5
|
设置新值并获取原来的值
# 会将原先的值先返回
print
(r.getset(
'name'
,
'Tom'
))
print
(r.get(
'name'
))
|
9. getrange(key, start, end)
1
2
3
4
5
6
|
如果是中文字符,在utf
-
8
编码下,一个中文字符占
3
个字节
r.
set
(
'address'
,
'杭州'
)
res
=
r.getrange(
'address'
,
0
,
2
)
print
(res.decode())
|
10. setrange(name, offset, value)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
# 修改字符串内容,从指定字符串索引开始向后替换(新值太长时,则向后添加)
# 参数:
# offset,字符串的索引,字节(一个汉字三个字节)
# value,要设置的值
r.setrange(
'address'
,
0
,
'苏'
)
print
(r.get(
'address'
).decode())
# 输出
苏州
r.setrange(
'name'
,
2
,
'ol'
)
print
(r.get(
'name'
).decode())
# 输出
Tool
# Tom 变成了 Tool
|
11. setbit(name, offset, value)
*用途举例,用最省空间的方式,存储在线用户数及分别是哪些用户在线
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
# 对name对应值的二进制表示的位进行操作
# 参数:
# name,redis的name
# offset,位的索引(将值变换成二进制后再进行索引)
# value,值只能是 1 或 0
# 注:如果在Redis中有一个对应: n1 = "foo",
那么字符串foo的二进制表示为:
01100110
01101111
01101111
所以,如果执行 setbit(
'n1'
,
7
,
1
),则就会将第
7
位设置为
1
,
那么最终二进制则变成
01100111
01101111
01101111
,即:
"goo"
#我们将Tool 改变为 Pool
#则需要将T的ascii值 改为 P 的ASCII值
print
(r.get(
'name'
))
r.setbit(
'name'
,
5
,
0
)
print
(r.get(
'name'
))
# 输出
b
'Tool'
b
'Pool'
|
12. getbit(name, offset)
1
2
3
4
5
6
|
# 获取name对应的值的二进制表示中的某位的值 (0或1)
print
(r.getbit(
'name'
,
3
))
# 输出
1
|
13. bitcount(key, start=None, end=None)
1
2
3
4
5
6
7
8
9
10
11
|
# 获取name对应的值的二进制表示中 1 的个数
# 参数:
# key,Redis的name
# start,位起始位置
# end,位结束位置
print
(r.bitcount(
'name'
,
0
,
20
))
# 输出
18
|
14. strlen(name)
1
2
3
4
5
6
|
# 返回name对应值的字节长度(一个汉字3个字节)
print
(r.strlen(
'address'
))
# 输出
6
|
15. incr(self, name, amount=1)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
# 自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。
# 参数:
# name,Redis的name
# amount,自增数(必须是整数)
for
i
in
range
(
5
):
print
(r.incr(
'login_user'
))
#输出
1
2
3
4
5
|
16. incrbyfloat(self, name, amount=1.0)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
# 自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。
# 参数:
# name,Redis的name
# amount,自增数(浮点型)
for
i
in
range
(
5
):
print
(r.incrbyfloat(
'num'
,
1.2
))
# 输出
1.2
2.4
3.6
4.8
6.0
|
17. decr(self, name, amount=1)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
# 自减 name对应的值,当name不存在时,则创建name=amount,否则,则自减。
# 参数:
# name,Redis的name
# amount,自减数(整数)
for
i
in
range
(
5
):
print
(r.decr(
'login_user'
))
# 输出
4
3
2
1
0
|
18. append(key, value)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
# 在redis name对应的值后面追加内容
# 参数:
key, redis的name
value, 要追加的字符串
print
(r.get(
'address'
).decode())
print
(r.append(
'address'
,
'西湖区'
))
print
(r.get(
'address'
).decode())
# 输出
杭州
15
杭州西湖区
|
一、Redis的介绍
redis是业界主流的key-value nosql 数据库之一。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。
二、Redis的优点
-
异常快速 : Redis是非常快的,每秒可以执行大约110000设置操作,81000个/每秒的读取操作。
-
支持丰富的数据类型 : Redis支持最大多数开发人员已经知道如列表,集合,可排序集合,哈希等数据类型。这使得在应用中很容易解决的各种问题,因为我们知道哪些问题处理使用哪种数据类型更好解决。
-
操作都是原子的 : 所有 Redis 的操作都是原子,从而确保当两个客户同时访问 Redis 服务器得到的是更新后的值(最新值)。
-
MultiUtility工具:Redis是一个多功能实用工具,可以在很多如:缓存,消息传递队列中使用(Redis原生支持发布/订阅),在应用程序中,如:Web应用程序会话,网站页面点击数等任何短暂的数据
三、Redis API使用
redis-py 的API的使用可以分类为:
- 连接方式
- 连接池
- 操作
- String 操作
- Hash 操作
- List 操作
- Set 操作
- Sort Set 操作
- 管道
- 发布订阅
3.1 连接方式
1. 操作模式
redis-py提供两个类Redis和StrictRedis用于实现Redis的命令,StrictRedis用于实现大部分官方的命令,并使用官方的语法和命令,Redis是StrictRedis的子类,用于向后兼容旧版本的redis-py。
1
2
3
4
5
6
7
8
9
|
import
redis
host
=
'172.16.200.49'
port
=
6379
r
=
redis.Redis(host
=
host, port
=
port)
r.
set
(
'foo'
,
'bar'
)
print
(r.get(
'foo'
))
|
2. 连接池
redis-py使用connection pool来管理对一个redis server的所有连接,避免每次建立、释放连接的开销。默认,每个Redis实例都会维护一个自己的连接池。可以直接建立一个连接池,然后作为参数Redis,这样就可以实现多个Redis实例共享一个连接池。
1
2
3
4
5
6
7
8
9
10
11
|
import
redis
host
=
'172.16.200.49'
port
=
6379
pool
=
redis.ConnectionPool(host
=
host, port
=
port)
r
=
redis.Redis(connection_pool
=
pool)
r.
set
(
'foo'
,
'bar'
)
print
(r.get(
'foo'
))
|
3.1 string操作
redis中的String在在内存中按照一个name对应一个value来存储。如图:
1.set(name, value, ex=None, px=None, nx=False, xx=False)
1
2
3
4
5
6
|
在Redis中设置值,默认,不存在则创建,存在则修改
参数:
ex,过期时间(秒)
px,过期时间(毫秒)
nx,如果设置为
True
,则只有name不存在时,当前
set
操作才执行
xx,如果设置为
True
,则只有name存在时,岗前
set
操作才执行
|
操作命令
1
2
3
4
5
6
7
8
9
10
|
# 设置一个k-v
r.
set
(
'name'
,
'bigberg'
)
print
(r.get(
'name'
))
#设置过期时间为2秒
# 2 秒后获取该值为None
r.
set
(
'name'
,
'bigberg'
, ex
=
2
)
print
(r.get(
'name'
))
time.sleep(
2
)
print
(r.get(
'name'
))
|
2. setnx(name, value)
1
2
3
4
5
6
|
设置值,只有name不存在时,执行设置操作(添加)
如果是r.setnx(
'name'
,
'Tom'
) 则name的值还是
'bigberg'
r.setnx(
'age'
,
22
)
print
(r.get(
'age'
))
|
3. setex(name, value, time)
1
2
3
|
# 设置值
# 参数:
# time,过期时间(数字秒 或 timedelta对象)
|
4. psetex(name, time_ms, value)
1
2
3
|
# 设置值
# 参数:
# time_ms,过期时间(数字毫秒 或 timedelta对象)
|
5. mset(*args, **kwargs)
1
2
3
4
5
6
7
8
|
批量设置值
如:
mset({
'k1'
:
'v1'
,
'k2'
:
'v2'
})
r.mset({
'a'
:
1
,
'b'
:
2
})
print
(r.get(
'a'
))
print
(r.get(
'b'
))
|
6. get(name)
1
|
获取值
|
7. mget(keys, *args)
1
2
3
4
5
6
7
8
9
|
批量获取
如:
mget(
'ylr'
,
'wupeiqi'
)
或
r.mget([
'ylr'
,
'wupeiqi'
])
r.mset({
'a'
:
1
,
'b'
:
2
})
print
(r.mget(
'a'
,
'b'
))
|
8. getset(name, value)
1
2
3
4
5
|
设置新值并获取原来的值
# 会将原先的值先返回
print
(r.getset(
'name'
,
'Tom'
))
print
(r.get(
'name'
))
|
9. getrange(key, start, end)
1
2
3
4
5
6
|
如果是中文字符,在utf
-
8
编码下,一个中文字符占
3
个字节
r.
set
(
'address'
,
'杭州'
)
res
=
r.getrange(
'address'
,
0
,
2
)
print
(res.decode())
|
10. setrange(name, offset, value)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
# 修改字符串内容,从指定字符串索引开始向后替换(新值太长时,则向后添加)
# 参数:
# offset,字符串的索引,字节(一个汉字三个字节)
# value,要设置的值
r.setrange(
'address'
,
0
,
'苏'
)
print
(r.get(
'address'
).decode())
# 输出
苏州
r.setrange(
'name'
,
2
,
'ol'
)
print
(r.get(
'name'
).decode())
# 输出
Tool
# Tom 变成了 Tool
|
11. setbit(name, offset, value)
*用途举例,用最省空间的方式,存储在线用户数及分别是哪些用户在线
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
# 对name对应值的二进制表示的位进行操作
# 参数:
# name,redis的name
# offset,位的索引(将值变换成二进制后再进行索引)
# value,值只能是 1 或 0
# 注:如果在Redis中有一个对应: n1 = "foo",
那么字符串foo的二进制表示为:
01100110
01101111
01101111
所以,如果执行 setbit(
'n1'
,
7
,
1
),则就会将第
7
位设置为
1
,
那么最终二进制则变成
01100111
01101111
01101111
,即:
"goo"
#我们将Tool 改变为 Pool
#则需要将T的ascii值 改为 P 的ASCII值
print
(r.get(
'name'
))
r.setbit(
'name'
,
5
,
0
)
print
(r.get(
'name'
))
# 输出
b
'Tool'
b
'Pool'
|
12. getbit(name, offset)
1
2
3
4
5
6
|
# 获取name对应的值的二进制表示中的某位的值 (0或1)
print
(r.getbit(
'name'
,
3
))
# 输出
1
|
13. bitcount(key, start=None, end=None)
1
2
3
4
5
6
7
8
9
10
11
|
# 获取name对应的值的二进制表示中 1 的个数
# 参数:
# key,Redis的name
# start,位起始位置
# end,位结束位置
print
(r.bitcount(
'name'
,
0
,
20
))
# 输出
18
|
14. strlen(name)
1
2
3
4
5
6
|
# 返回name对应值的字节长度(一个汉字3个字节)
print
(r.strlen(
'address'
))
# 输出
6
|
15. incr(self, name, amount=1)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
# 自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。
# 参数:
# name,Redis的name
# amount,自增数(必须是整数)
for
i
in
range
(
5
):
print
(r.incr(
'login_user'
))
#输出
1
2
3
4
5
|
16. incrbyfloat(self, name, amount=1.0)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
# 自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。
# 参数:
# name,Redis的name
# amount,自增数(浮点型)
for
i
in
range
(
5
):
print
(r.incrbyfloat(
'num'
,
1.2
))
# 输出
1.2
2.4
3.6
4.8
6.0
|
17. decr(self, name, amount=1)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
# 自减 name对应的值,当name不存在时,则创建name=amount,否则,则自减。
# 参数:
# name,Redis的name
# amount,自减数(整数)
for
i
in
range
(
5
):
print
(r.decr(
'login_user'
))
# 输出
4
3
2
1
0
|
18. append(key, value)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
# 在redis name对应的值后面追加内容
# 参数:
key, redis的name
value, 要追加的字符串
print
(r.get(
'address'
).decode())
print
(r.append(
'address'
,
'西湖区'
))
print
(r.get(
'address'
).decode())
# 输出
杭州
15
杭州西湖区
|