day_11_python
一、MySQL分组连表和外键补充
数据库中表表之间的关系
a. 单表
b. 一对多
用户类型表: 1 超级用户 2 普通用户 3 二笔用户 # 就是该表中该行可以对应用户中的很多行 用户表: 方式器 3(设置数字,约束=外键(表,列)) 刘浩 6 何磊 3 何磊 3
c. 多对多( )
1.第三张表分别对应不同的表
主机信息表: 1 c1.com 2 c1.com 3 c1.com 4 c1.com 用户表信息表: 1 严选育 2 卢饶 3 泥泞 4 利用三 装机记录表: 用户 主机 时间 4 1 83 4 2 83 4 1 93 4 2 93 3 2 93
2.单张表中的对应关系
相亲人员表: 1 严选育 2 卢饶 3 泥泞 4 利用三 相亲记录表: 男 女 4 3() 4 3 4 2 1 3 +联合唯一约束:(男 女)
group by
- 对列进行聚合 sum(sid),max(sid),min(sid),count(sid)
- 聚合条件过滤,having count(sid) > 7
SELECT * from student select class_id,count(sid),sum(sid),min(sid) from student GROUP BY class_id
连表操作
- inner join: 不会出现null
- left join: 左侧,有多少显示多少,连表无对应项: null
- right join

SELECT * from student SELECT student.sid,student.sname,class.caption from student LEFT JOIN class on student.class_id = class.cid SELECT A.sid,A.sname,B.caption from student as A LEFT JOIN class as B on A.class_id = B.cid SELECT A.sid as SSS,A.sname,B.caption from student as A LEFT JOIN class as B on A.class_id = B.cid ---------------------------------------------------------------------------------------------------- SELECT * from score LEFT JOIN student on score.student_id = student.sid LEFT JOIN class on student.class_id = class.cid LEFT JOIN course on score.course_id = course.cid LEFT JOIN teacher on course.teacher_id = teacher.tid
使用外键的优缺点
FK:
- 储存省
- 查询慢
优点:程序员省事
No FK:
- 存储不省
- 查询快
优点:查询快
缺点:程序员维护数据
Django:神奇的双下划线
二、memcached操作
Memcached是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。
它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态、数据库驱动网站的速度。
Memcached基于一个存储键/值对的hashmap。其守护进程(daemon )是用C写的,但是客户端可以用任何语言来编写,
并通过memcached协议与守护进程通信。其只能处理字符串这种数据类型。
ubuntu16.4 memcache安装
参考博客:http://blog.chinaunix.net/uid-21633169-id-4313689.html
服务器端:
apt install memcached
memcached -u root -p 1234 -m 128 -d start -c 1024 -l 0.0.0.0
lsof -i:1234
pkill memcached
python-memcache
这里需要说明一下memcached服务的启动参数:
-p 监听的端口
-l 连接的IP地址, 默认是本机
-d start 启动memcached服务
-d restart 重起memcached服务
-d stop|shutdown 关闭正在运行的memcached服务
-d install 安装memcached服务
-d uninstall 卸载memcached服务
-u 以的身份运行 (仅在以root运行的时候有效)
-m 最大内存使用,单位MB。默认64MB
-M 内存耗尽时返回错误,而不是删除项
-c 最大同时连接数,默认是1024
-f 块大小增长因子,默认是1.25-n 最小分配空间,key+value+flags默认是48
-h 显示帮助
python客户端:
python客户端安装python-memcached
1、第一次操作
import memcache mc = memcache.Client(['192.168.0.102:1234'], debug=True) mc.set("foo", "bar") res = mc.get('foo') print(res)
Ps:debug = True 表示运行出现错误时,现实错误信息,上线后移除该参数。
2、天生支持集群
python-memcached模块原生支持集群操作,其原理是在内存维护一个主机列表,且集群中主机的权重值和主机在列表中重复出现的次数成正比
主机 权重 1.1.1.1 1 1.1.1.2 2 1.1.1.3 1 那么在内存中主机列表为: host_list = ["1.1.1.1", "1.1.1.2", "1.1.1.2", "1.1.1.3", ]
如果用户根据如果要在内存中创建一个键值对(如:k1 = "v1"),那么要执行一下步骤:
• 根据算法将 k1 转换成一个数字
• 将数字和主机列表长度求余数,得到一个值 N( 0 <= N < 列表长度 )
• 在主机列表中根据第2步得到的值为索引获取主机,例如:host_list[N]
• 连接 将第3步中获取的主机,将 k1 = "v1" 放置在该服务器的内存中
代码实现如下:
mc = memcache.Client([('1.1.1.1:12000', 1), ('1.1.1.2:12000', 2), ('1.1.1.3:12000', 1)], debug=True) mc.set('k1', 'v1')
3、add
添加一条键值对,如果已经存在的 key,重复执行add操作异常
import memcache mc = memcache.Client(['10.211.55.4:12000'], debug=True) mc.add('k1', 'v1') # mc.add('k1', 'v2') # 报错,对已经存在的key重复添加,失败!!!
4、replace
replace 修改某个key的值,如果key不存在,则异常
import memcache mc = memcache.Client(['10.211.55.4:12000'], debug=True) # 如果memcache中存在kkkk,则替换成功,否则一场 mc.replace('kkkk','999')
5、set 和 set_multi
set 设置一个键值对,如果key不存在,则创建,如果key存在,则修改
set_multi 设置多个键值对,如果key不存在,则创建,如果key存在,则修改
import memcache mc = memcache.Client(["192.168.100.243:1234"],debug=True) mc.set("key0","peiqi") mc.set_multi({"key1":"gaohui","key2":"yanglun"}) print(mc.get("key0")) print(mc.get("key1")) print(mc.get("key2"))
6、delete 和 delete_multi
delete 在Memcached中删除指定的一个键值对
delete_multi 在Memcached中删除指定的多个键值对
import memcache mc = memcache.Client(['10.211.55.4:12000'], debug=True) mc.delete('key0') mc.delete_multi(['key1', 'key2'])
7、get 和 get_multi
get 获取一个键值对
get_multi 获取多一个键值对
import memcache mc = memcache.Client(['10.211.55.4:12000'], debug=True) val = mc.get('key0') item_dict = mc.get_multi(["key1", "key2", "key3"])
8、append 和 prepend
append 修改指定key的值,在该值后面 追加内容
prepend 修改指定key的值,在该值前面 插入内容
import memcache mc = memcache.Client(['10.211.55.4:12000'], debug=True) # k1 = "v1" mc.append('k1', 'after') # k1 = "v1after" mc.prepend('k1', 'before') # k1 = "beforev1after"
9、decr 和 incr
incr 自增,将Memcached中的某一个值增加 N ( N默认为1 )
decr 自减,将Memcached中的某一个值减少 N ( N默认为1 )
import memcache mc = memcache.Client(['10.211.55.4:12000'], debug=True) mc.set('k1', '777') mc.incr('k1') # k1 = 778 mc.incr('k1', 10) # k1 = 788 mc.decr('k1') # k1 = 787 mc.decr('k1', 10) # k1 = 777
10、gets 和 cas (对共享数据进行修改,保证数据的唯一性)
如商城商品剩余个数,假设改值保存在memcache中,product_count = 900
A用户刷新页面从memcache中读取到product_count = 900
B用户刷新页面从memcache中读取到product_count = 900
如果A、B用户均购买商品
A用户修改商品剩余个数 product_count=899
B用户修改商品剩余个数 product_count=899
如此一来缓存内的数据便不在正确,两个用户购买商品后,商品剩余还是 899
如果使用python的set和get来操作以上过程,那么程序就会如上述所示情况!
如果想要避免此情况的发生,只要使用 gets 和 cas 即可,如:
import memcache mc = memcache.Client(['10.211.55.4:12000'], debug=True, cache_cas=True) v = mc.gets('product_count') # 如果有人在gets之后和cas之前修改了product_count,那么,下面的设置将会执行失败,剖出异常,从而避免非正常数据的产生 mc.cas('product_count', "899")
自己测试:
s1.py
import memcache conn = memcache.Client(["192.168.0.102:1234"],debug=True,cache_cas=True) conn.set("num",100) v = conn.gets("num") print(v) import time time.sleep(5) conn.cas("num",95) print(conn.get("num"))
s2.py
import memcache conn = memcache.Client(["192.168.0.102:1234"],debug=True,cache_cas=True) v = conn.gets("num") print(v) conn.cas("num",99) # gets和cas方法使用
Ps:本质上每次执行gets时,会从memcache中获取一个自增的数字,通过cas去修改gets的值时,会携带之前获取的自增值和memcache中的自增值进行比较,如果相等,则可以提交,如果不想等,那表示在gets和cas执行之间,又有其他人执行了gets(获取了缓冲的指定值), 如此一来有可能出现非正常数据,则不允许修改。
三、redis相关操作
redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。
ubuntu16.4 redis安装
参考博客:http://blog.csdn.net/qq_30242609/article/details/52913145
redis服务端:
apt search redis-server
apt install redis-server
ps -aux | grep redis
lsof -i:6379
修改Redis的配置
使用Redis的访问账号
requirepass redis
让Redis服务器被远程访问
# bind 127.0.0.1
/etc/init.d/redis-server restart
lsof -i:6379
python客户端:
操作redis
pip3 install redis
API使用
redis-py 的API的使用可以分类为:
• 连接方式
• 连接池
• 操作
• String 操作
• Hash 操作
• List 操作
• Set 操作
• Sort Set 操作
• 管道
• 发布订阅
1、操作模式
redis-py提供两个类Redis和StrictRedis用于实现Redis的命令,StrictRedis用于实现大部分官方的命令,并使用官方的语法和命令,Redis是StrictRedis的子类,用于向后兼容旧版本的redis-py。
r = redis.Redis(host = "192.168.100.243",port = 6379,db = 0,password="redis") #如果设置了密码,就加上password=密码
import redis r = redis.Redis(host = "192.168.100.243",port = 6379) r.set("foo","bar") print(r.get("foo"))
2、连接池
redis-py使用connection pool来管理对一个redis server的所有连接,避免每次建立、释放连接的开销。默认,每个Redis实例都会维护一个自己的连接池。可以直接建立一个连接池,然后作为Redis的参数,这样就可以实现多个Redis实例共享一个连接池。
import redis pool = redis.ConnectionPool(host = "192.168.100.243",port = 6379) r = redis.Redis(connection_pool=pool) r.set("k1","v1") print(r.get("foo"))
3、数据类型操作
String操作,redis中的String在在内存中按照一个name对应一个value来存储。如图:

set(name, value, ex=None, px=None, nx=False, xx=False) # 在Redis中设置值,默认,不存在则创建,存在则修改
参数: ex,过期时间(秒) px,过期时间(毫秒) nx,如果设置为True,则只有name不存在时,当前set操作才执行 xx,如果设置为True,则只有name存在时,当前set操作才执行 import redis import time pool = redis.ConnectionPool(host = "192.168.100.243",port = 6379) r = redis.Redis(connection_pool=pool) r.set("k2","v2",px=1) print(r.get("k2")) time.sleep(2) print(r.get("k2"))
setnx(name, value) # 设置值,只有name不存在时,执行设置操作(添加)
import redis r = redis.Redis(host="192.168.100.243",port=6379) r.setnx("k3","v3")
setex(name, value, time) # 设置值
# 参数: # time,过期时间(数字秒 或 timedelta对象) import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.setex("k3","v3",1) print(r.get("k3")) time.sleep(2) print(r.get("k3"))
psetex(name, time_ms, value) # 毫秒设置过期时间-毫秒级别
# 设置值 # 参数: # time_ms,过期时间(数字毫秒 或 timedelta对象)
mset(*args, **kwargs) # 批量设置值
mset(k1='v1', k2='v2') 或 mset({'k1': 'v1', 'k2': 'v2'}) import redis import time r = redis.Redis(host="192.168.100.243",port=6379) # r.mset(k1="v1",k2="v2") r.mset({"k1":"v1","k2":"v2"}) print(r.get("k2"))
get(name) # 获取值
import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.set("k1","高辉") print(r.get("k1"))
mget(keys, *args) # 批量获取
mget('ylr', 'wupeiqi') 或 r.mget(['ylr', 'wupeiqi']) import redis import time r = redis.Redis(host="192.168.100.243",port=6379) # r.mset(k1="v1",k2="v2") r.mset({"k1":"v1","k2":"v2"}) print(r.mget("k1","k2"))
getset(name, value) # 设置新值并获取原来的值
import redis import time r = redis.Redis(host="192.168.100.243",port=6379) print(r.getset("k1","gaohui"))
getrange(key, start, end) # 获取子序列(根据字节获取,非字符)
# 参数: # name,Redis 的 name # start,起始位置(字节) # end,结束位置(字节) # 如: "武沛齐" ,0-3表示 "武" import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.set("k1","高辉") print(r.getrange("k1",0,2).decode())
setrange(name, offset, value) # 修改字符串内容,从指定字符串索引开始向后替换(新值太长时,则向后添加)
# 参数: # offset,字符串的索引,字节(一个汉字三个字节) # value,要设置的值 import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.set("k1","高辉") r.setrange("k1",3,"兴") print(r.getrange("k1",0,5).decode())
setbit(name, offset, value) # 对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" # 扩展,转换二进制表示: # source = "武沛齐" source = "foo" for i in source: num = ord(i) print bin(num).replace('b','') 特别的,如果source是汉字 "武沛齐"怎么办? 答:对于utf-8,每一个汉字占 3 个字节,那么 "武沛齐" 则有 9个字节 对于汉字,for循环时候会按照 字节 迭代,那么在迭代时,将每一个字节转换 十进制数,然后再将十进制数转换成二进制 11100110 10101101 10100110 11100110 10110010 10011011 11101001 10111101 10010000 -------------------------- ----------------------------- ----------------------------- 武 沛 齐
getbit(name, offset) # 获取name对应的值的二进制表示中的某位的值 (0或1)
import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.set("k1","v1") print(r.getbit("k1",1))
bitcount(key, start=None, end=None) # 获取name对应的值的二进制表示中 1 的个数
# 参数: # key,Redis的name # start,位起始位置 # end,位结束位置 import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.set("k1","v1") print(r.bitcount("k1"))
bitop(operation, dest, *keys) # 获取多个值,并将值做位运算,将最后的结果保存至新的name对应的值
# 参数: # operation,AND(并) 、 OR(或) 、 NOT(非) 、 XOR(异或) # dest, 新的Redis的name # *keys,要查找的Redis的name # 如: bitop("AND", 'new_name', 'n1', 'n2', 'n3') # 获取Redis中n1,n2,n3对应的值,然后讲所有的值做位运算(求并集),然后将结果保存 new_name 对应的值中 import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.mset({"k1":"v1","k2":"v2","k3":"v3"}) print(r.get("k1")) print(r.get("k2")) print(r.get("k3")) r.bitop("and","new_name","k1","k2","k3") print(r.get("new_name"))
strlen(name) # 返回name对应值的字节长度(一个汉字3个字节)
import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.set("k4","高辉") print(r.strlen("k4"))
incr(self, name, amount=1) # 自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增
# 参数: # name,Redis的name # amount,自增数(必须是整数) # 注:同incrby import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.incr("k5",amount = 10) print(r.get("k5"))
incrbyfloat(self, name, amount=1.0) # 自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增
# 参数: # name,Redis的name # amount,自增数(浮点型) import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.set("k5",1) r.incrbyfloat("k5",amount = 10.5) print(r.get("k5"))
decr(self, name, amount=1) # 自减 name对应的值,当name不存在时,则创建name=amount,否则,则自减
# 参数: # name,Redis的name # amount,自减数(整数) import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.set("k5",10) print(r.get("k5")) r.decr("k5",amount = 1) print(r.get("k5"))
append(key, value) # 在redis name对应的值后面追加内容
# 参数: key, redis的name value, 要追加的字符串 import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.set("k6","happy") print(r.get("k6")) r.append("k6","day") print(r.get("k6"))
Hash操作
redis中Hash在内存中的存储格式如下图:

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 r = redis.Redis(host="192.168.100.243",port=6379) r.hset("test","k6","happy") print(r.hget("test","k6"))
hmset(name, mapping) # 在name对应的hash中批量设置键值对
# 参数: # name,redis的name # mapping,字典,如:{'k1':'v1', 'k2': 'v2'} # 如: # r.hmset('xx', {'k1':'v1', 'k2': 'v2'}) import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.hmset("test",{"k1":"v1","k2":"v2"}) print(r.hmget("test",["k1","k2","k3"]))
hget(name,key) # 在name对应的hash中获取根据key获取value
import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.hset("test","k6","happy") print(r.hget("test","k6"))
hmget(name, keys, *args) # 在name对应的hash中获取多个key的值
# 参数: # name,reids对应的name # keys,要获取key集合,如:['k1', 'k2', 'k3'] # *args,要获取的key,如:k1,k2,k3 # 如: # r.mget('xx', ['k1', 'k2']) # 或 # print r.hmget('xx', 'k1', 'k2') import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.hmset("test",{"k1":"v1","k2":"v2"}) print(r.hmget("test","k1","k2","k3"))
hgetall(name) # 获取name对应hash的所有键值
import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.hmset("test",{"k1":"v1","k2":"v2"}) print(r.hgetall("test"))
hlen(name) # 获取name对应的hash中键值对的个数
import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.hmset("test",{"k1":"v1","k2":"v2"}) print(r.hlen("test"))
hkeys(name) # 获取name对应的hash中所有的key的值
import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.hmset("test",{"k1":"v1","k2":"v2"}) print(r.hkeys("test"))
hvals(name) # 获取name对应的hash中所有的value的值
import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.hmset("test",{"k1":"v1","k2":"v2"}) print(r.hvals("test"))
hexists(name, key) # 检查name对应的hash是否存在当前传入的key
import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.hmset("test",{"k1":"v1","k2":"v2"}) print(r.hexists("test","k1"))
hdel(name,*keys) # 将name对应的hash中指定key的键值对删除
import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.hmset("test",{"k1":"v1","k2":"v2"}) r.hdel("test","k1") print(r.hexists("test","k1"))
hincrby(name, key, amount=1)
# 自增name对应的hash中的指定key的值,不存在则创建key=amount # 参数: # name,redis中的name # key, hash对应的key # amount,自增数(整数) import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.hmset("test",{"k1":5,"k2":"v2"}) r.hincrby("test","k1",amount=1) print(r.hget("test","k1"))
hincrbyfloat(name, key, amount=1.0) # 自增name对应的hash中的指定key的值,不存在则创建key=amount
# 参数: # name,redis中的name # key, hash对应的key # amount,自增数(浮点数) # 自增name对应的hash中的指定key的值,不存在则创建key=amount import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.hmset("test",{"k1":5,"k2":"v2"}) r.hincrbyfloat("test","k1",amount=1.5) print(r.hget("test","k1"))
hscan(name, cursor=0, match=None, count=None)
# 增量式迭代获取,对于数据大的数据非常有用,hscan可以实现分片的获取数据,并非一次性将数据全部获取完,从而放置内存被撑爆
# 参数: # name,redis的name # cursor,游标(基于游标分批取获取数据) # match,匹配指定key,默认None 表示所有的key # count,每次分片最少获取个数,默认None表示采用Redis的默认分片个数 # 如: # 第一次:cursor1, data1 = r.hscan('xx', cursor=0, match=None, count=None) # 第二次:cursor2, data1 = r.hscan('xx', cursor=cursor1, match=None, count=None) # 直到返回值cursor的值为0时,表示数据已经通过分片获取完毕 import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.hmset("test",{"k1":"v1","k2":"v2","k3":"v3","k4":"v4","k5":"v5"}) cursor1,data = r.hscan("test",cursor=0,match=None,count=None) cursor2,data = r.hscan("test",cursor=cursor1,match=None,count=None) print(cursor2,data)
hscan_iter(name, match=None, count=None) # 利用yield封装hscan创建生成器,实现分批去redis中获取数据
# 参数: # match,匹配指定key,默认None 表示所有的key # count,每次分片最少获取个数,默认None表示采用Redis的默认分片个数 # 如: # for item in r.hscan_iter('xx'): # print item import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.hmset("test",{"k1":"v1","k2":"v2","k3":"v3","k4":"v4","k5":"v5"}) for item in r.hscan_iter("test"): print(item)
List操作
redis中的List在在内存中按照一个name对应一个List来存储。如图:

lpush(name,values) # 在name对应的list中添加元素,每个新的元素都添加到列表的最左边
# 如: # r.lpush('oo', 11,22,33) # 保存顺序为: 33,22,11 # 扩展: # rpush(name, values) 表示从右向左操作 import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.lpush("oo",11,22,33) print(r.lindex("oo",0)) import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.rpush("oo",44,55) print(r.lindex("oo",-1))
lpushx(name,value) # 在name对应的list中添加元素,只有name已经存在时,值添加到列表的最左边
# 更多: # rpushx(name, value) 表示从右向左操作 import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.lpushx("oo",66) print(r.lindex("oo",0)) r.rpushx("oo",66) r.rpushx("oo",77) print(r.lindex("oo",-1))
llen(name) # name对应的list元素的个数
import redis import time r = redis.Redis(host="192.168.100.243",port=6379) print(r.llen("oo"))
linsert(name, where, refvalue, value)) # 在name对应的列表的某一个值前或后插入一个新值
# 参数: # name,redis的name # where,BEFORE或AFTER # refvalue,标杆值,即:在它前后插入数据 # value,要插入的数据 import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.lpush("loo",11) print(r.lindex("loo",0)) r.linsert("loo","before",11,22) print(r.lindex("loo",0))
r.lset(name, index, value) # 对name对应的list中的某一个索引位置重新赋值
# 参数: # name,redis的name # index,list的索引位置 # value,要设置的值 import redis import time r = redis.Redis(host="192.168.100.243",port=6379) print(r.lindex("loo",0)) r.lset("loo",0,33) print(r.lindex("loo",0))
r.lrem(name, value, num) # 在name对应的list中删除指定的值
# 参数: # name,redis的name # value,要删除的值 # num, num=0,删除列表中所有的指定值; # num=2,从前到后,删除2个; # num=-2,从后向前,删除2个 import redis import time r = redis.Redis(host="192.168.100.243",port=6379) print(r.lindex("loo",0)) r.lrem("loo",33) print(r.lindex("loo",0))
lpop(name) # 在name对应的列表的左侧获取第一个元素并在列表中移除,返回值则是第一个元素
# 更多: # rpop(name) 表示从右向左操作 import redis import time r = redis.Redis(host="192.168.100.243",port=6379) print(r.lindex("loo",0)) r.lpop("loo") print(r.lindex("loo",0))
lindex(name, index) 在name对应的列表中根据索引获取列表元素
import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.lpush("oo",11,22,33) print(r.lindex("oo",0))
lrange(name, start, end) # 在name对应的列表分片获取数据
# 参数: # name,redis的name # start,索引的起始位置 # end,索引结束位置 import redis import time r = redis.Redis(host="192.168.100.243",port=6379) print(r.lindex("oo",0)) print(r.lrange("oo",0,2))
ltrim(name, start, end) # 在name对应的列表中移除没有在start-end索引之间的值
# 参数: # name,redis的name # start,索引的起始位置 # end,索引结束位置 import redis import time r = redis.Redis(host="192.168.100.243",port=6379) print(r.lindex("oo",-1)) print(r.llen("oo")) r.ltrim("oo",0,18) print(r.llen("oo"))
rpoplpush(src, dst) # 从一个列表取出最右边的元素,同时将其添加至另一个列表的最左边
# 参数: # src,要取数据的列表的name # dst,要添加数据的列表的name import redis import time r = redis.Redis(host="192.168.100.243",port=6379) print(r.lindex("oo",-1)) print(r.llen("oo")) print(r.llen("loo")) r.rpoplpush("oo","loo") print(r.llen("oo")) print(r.llen("loo"))
blpop(keys, timeout) # 将多个列表排列,按照从左到右去pop对应列表的元素
# 参数: # keys,redis的name的集合 # timeout,超时时间,当元素所有列表的元素获取完之后,阻塞等待列表内有数据的时间(秒), 0 表示永远阻塞 # 更多: # r.brpop(keys, timeout),从右向左获取数据 import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.blpop(("oo","loo"),5) print(r.llen("oo")) print(r.llen("loo"))
brpoplpush(src, dst, timeout=0) # 从一个列表的右侧移除一个元素并将其添加到另一个列表的左侧
# 参数: # src,取出并要移除元素的列表对应的name # dst,要插入元素的列表对应的name # timeout,当src对应的列表中没有数据时,阻塞等待其有数据的超时时间(秒),0 表示永远阻塞 import redis import time r = redis.Redis(host="192.168.100.243",port=6379) print(r.llen("oo")) print(r.llen("loo")) r.brpoplpush("oo","loo",timeout=2)
自定义增量迭代
# 由于redis类库中没有提供对列表元素的增量迭代,如果想要循环name对应的列表的所有元素,那么就需要: # 1、获取name对应的所有列表 # 2、循环列表 # 但是,如果列表非常大,那么就有可能在第一步时就将程序的内容撑爆,所有有必要自定义一个增量迭代的功能: def list_iter(name): """ 自定义redis列表增量迭代 :param name: redis中的name,即:迭代name对应的列表 :return: yield 返回 列表元素 """ list_count = r.llen(name) for index in xrange(list_count): yield r.lindex(name, index) # 使用 for item in list_iter('pp'): print item import redis import time r = redis.Redis(host="192.168.100.243",port=6379) def list_iter(name): list_count = r.llen(name) for index in r.lrange(name,0,list_count): yield index print(r.llen("oo"),r.lindex("oo",-1)) for item in list_iter("oo"): print(item)
Set操作,Set集合就是不允许重复的列表
sadd(name,values) # name对应的集合中添加元素
# name对应的集合中添加元素 import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.sadd("soo",11,22) print(r.smembers("soo"))
scard(name) 获取name对应的集合中元素个数
import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.sadd("soo",11,22) print(r.scard("soo"))
sdiff(keys, *args) 在第一个name对应的集合中且不在其他name对应的集合的元素集合
import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.sadd("soo",11,22) r.sadd("soo2",22,33) print(r.sdiff("soo","soo2")) 执行结果: {b'11'}
sdiffstore(dest, keys, *args) # 获取第一个name对应的集合中且不在其他name对应的集合,再将其新加入到dest对应的集合中
import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.sadd("soo",11,22) r.sdiff("soo2",22,33) r.sdiffstore("soo3","soo","soo2") print(r.smembers("soo")) print(r.smembers("soo2")) print(r.smembers("soo3"))
sinter(keys, *args) # 获取多一个name对应集合的交集
import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.sadd("soo",11,22) r.sdiff("soo2",22,33) print(r.sinter("soo","soo2"))
sinterstore(dest, keys, *args) # 获取多一个name对应集合的交集,再讲其加入到dest对应的集合中
import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.sadd("soo",11,22) r.sdiff("soo2",22,33) r.sinterstore("soo3","soo","soo2") print(r.smembers("soo3"))
sismember(name, value) # 检查value是否是name对应的集合的成员
import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.sadd("soo",11,22) print(r.sismember("soo",11))
smembers(name) # 获取name对应的集合的所有成员
import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.sadd("soo",11,22) print(r.smembers("soo"))
smove(src, dst, value) # 将某个成员从一个集合中移动到另外一个集合
import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.sadd("soo",11,22) r.smove("soo2","soo",33) print(r.smembers("soo"))
spop(name) # 从集合的右侧(尾部)移除一个成员,并将其返回
import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.sadd("soo",11,22) print(r.spop("soo"))
srandmember(name, numbers) # 从name对应的集合中随机获取 numbers 个元素
import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.sadd("soo",11,22,33,44,55,66) print(r.srandmember("soo",3))
srem(name, values) # 在name对应的集合中删除某些值
import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.sadd("soo",11,22,33,44,55,66) print(r.smembers("soo")) r.srem("soo",11) print(r.smembers("soo"))
sunion(keys, *args) # 获取多个name对应的集合的并集
import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.sadd("soo",11,22,33,44,55,66) r.sadd("soo2",55,66,77,88,99) print(r.smembers("soo")) print(r.smembers("soo2")) print(r.sunion("soo","soo2"))
sunionstore(dest,keys, *args) # 获取多一个name对应的集合的并集,并将结果保存到dest对应的集合中
import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.sadd("soo",11,22,33,44,55,66) r.sadd("soo2",55,66,77,88,99) print(r.smembers("soo")) print(r.smembers("soo2")) r.sunionstore("soo3","soo","soo2") print(r.smembers("soo3"))
sscan(name, cursor=0, match=None, count=None)
sscan_iter(name, match=None, count=None) # 同字符串的操作,用于增量迭代分批获取元素,避免内存消耗太大
import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.sadd("soo",11,22,33,44,55,66) print(r.smembers("soo")) print(r.sscan("soo",cursor=0,match=None,count=None))
有序集合,在集合的基础上,为每个元素排序;元素的排序需要根据另外一个值来进行比较,所以,对于有序集合,每一个元素有两个值,即:值和分数,分数专门用来做排序。
zadd(name, *args, **kwargs) # 在name对应的有序集合中添加元素
# 如: # zadd('zz', 'n1', 1, 'n2', 2) # 或 # zadd('zz', n1=11, n2=22) import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.zadd("zz","n1",1,"n2",2) print(r.zcard("zz"))
zcard(name) # 获取name对应的有序集合元素的数量
import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.zadd("zz","n1",1,"n2",2) print(r.zcard("zz"))
zcount(name, min, max) # 获取name对应的有序集合中分数 在 [min,max] 之间的个数
import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.zadd("zz","n1",1,"n2",2,"n3",3,"n4",4,"n5",5,"n6",6) print(r.zcount("zz",3,5))
zincrby(name, value, amount) # 自增name对应的有序集合的 name 对应的分数
redis有序集合未完,待续
其他常用操作
delete(*names) # 根据删除redis中的任意数据类型
import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.set("k1","v1") print(r.get("k1")) r.delete("k1") print(r.get("k1"))
exists(name) # 检测redis的name是否存在
import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.set("k1","v1") print(r.get("k1")) print(r.exists("k1"))
keys(pattern='*') # 根据模型获取redis的name
# 更多: # KEYS * 匹配数据库中所有 key 。 # KEYS h?llo 匹配 hello , hallo 和 hxllo 等。 # KEYS h*llo 匹配 hllo 和 heeeeello 等。 # KEYS h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.set("k1","v1") print(r.get("k1")) print(r.keys(pattern="k*"))
expire(name ,time) # 为某个redis的某个name设置超时时间
import redis import time r = redis.Redis(host="192.168.100.243",port=6379) r.set("k1","v1") print(r.get("k1")) r.expire("k1",1) time.sleep(2) print(r.get("k1"))
4、管道
redis-py默认在执行每次请求都会创建(连接池申请连接)和断开(归还连接池)一次连接操作,如果想要在一次请求中指定多个命令,则可以使用pipline实现一次请求指定多个命令,并且默认情况下一次pipline 是原子性操作。
import redis pool = redis.ConnectionPool(host='10.211.55.4', port=6379) r = redis.Redis(connection_pool=pool) # pipe = r.pipeline(transaction=False) pipe = r.pipeline(transaction=True) pipe.set('name', 'alex') pipe.set('role', 'sb') pipe.execute() print(r.get("name"))
5、发布订阅

Demo如下:
RedisHelper.py
import redis class RedisHelper: def __init__(self): self.__conn = redis.Redis(host='10.211.55.4') self.chan_sub = 'fm104.5' self.chan_pub = 'fm104.5' def public(self, msg): self.__conn.publish(self.chan_pub, msg) return True def subscribe(self): pub = self.__conn.pubsub() pub.subscribe(self.chan_sub) pub.parse_response() return pub
发布者:服务器
from monitor.RedisHelper import RedisHelper obj = RedisHelper() obj.public('hello')
订阅者:Dashboad和数据处理
from monitor.RedisHelper import RedisHelper obj = RedisHelper() redis_sub = obj.subscribe() while True: msg= redis_sub.parse_response() print(msg)
四、rabbitmq操作
RabbitMQ
RabbitMQ是一个在AMQP基础上完整的,可复用的企业消息系统。他遵循Mozilla Public License开源协议。
MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法。应用程序通过读写出入队列的消息(针对应用程序的数据)来通信,而无需专用连接来链接它们。消息传递指的是程序之间通过在消息中发送数据进行通信,而不是通过直接调用彼此来通信,直接调用通常是用于诸如远程过程调用的技术。排队指的是应用程序通过队列来通信。队列的使用除去了接收和发送应用程序同时执行的要求。
ubuntu16.4 RabbitMQ安装
RabbitMQ服务端:
apt search rabbitmq-server
apt install rabbitmq-server
ps aux | grep rabbitmq-server
对RabbitMQ服务端进行用户名的添加和授权:
rabbitmqctl add_user gaohui gaohui
rabbitmqctl set_user_tags gaohui administrator
rabbitmqctl set_permissions -p / gaohui "." "." ".*"
rabbitmqctl list_queues
Python操作RabbitMQ模块:
pip install pika
使用API操作RabbitMQ
基于Queue实现生产者消费者模型
import queue import threading message = queue.Queue(10) def producer(i): while True: message.put(i) def consumer(i): while True: msg = message.get() print(msg) for i in range(12): t = threading.Thread(target=producer, args=(i,)) t.start() for i in range(10): t = threading.Thread(target=consumer, args=(i,)) t.start()
rabbitmq实现消息队列
对于RabbitMQ来说,生产和消费不再针对内存里的一个Queue对象,而是某台服务器上的RabbitMQ Server实现的消息队列。
先运行消费者脚本,让它监听队列消息,然后运行生产者脚本,生产者往队列里发消息。然后消费者往队列里取消息。
消费者:
import pika # ########################### 消费者 ########################### credentials = pika.PlainCredentials('gaohui', 'gaohui') # connection = pika.BlockingConnection(pika.ConnectionParameters(host=url_1, # credentials=credentials, ssl=ssl, port=port)) connection = pika.BlockingConnection(pika.ConnectionParameters( host='192.168.100.243',credentials=credentials)) channel = connection.channel() channel.queue_declare(queue='abc') # 如果队列没有创建,就创建这个队列 def callback(ch, method, propertities,body): print(" [x] Received %r" % body) channel.basic_consume(callback, queue='abc', # 队列名 no_ack=True) # 不通知已经收到,如果连接中断可能消息丢失 print(' [*] Waiting for message. To exit press CTRL+C') channel.start_consuming()
生产者:
import pika # ############################## 生产者 ############################## credentials = pika.PlainCredentials('gaohui', 'gaohui') connection = pika.BlockingConnection(pika.ConnectionParameters( host='192.168.100.243',credentials=credentials)) channel = connection.channel() channel.queue_declare(queue='abc') # 如果队列没有创建,就创建这个队列 channel.basic_publish(exchange='', # exchange表示交换器,能精确指定消息应该发送到哪个队列 routing_key='abc', # 指定队列的关键字为,这里是队列的名字 body='Hello World!') # 往队列里发的消息内容 print(" [x] Sent 'Hello World!'") connection.close()
1、acknowledgment 消息不丢失
no-ack = False,如果消费者遇到情况(its channel is closed, connection is closed, or TCP connection is lost)挂掉了,那么,RabbitMQ会重新将该任务添加到队列中。
消费者:
import pika # ########################### 消费者 ########################### credentials = pika.PlainCredentials('gaohui', 'gaohui') # connection = pika.BlockingConnection(pika.ConnectionParameters(host=url_1, # credentials=credentials, ssl=ssl, port=port)) connection = pika.BlockingConnection(pika.ConnectionParameters( host='192.168.100.243',credentials=credentials)) channel = connection.channel() channel.queue_declare(queue='abc') # 如果队列没有创建,就创建这个队列 def callback(ch, method, propertities,body): print(" [x] Received %r" % body) import time time.sleep(10) print("ok") ch.basic_ack(delivery_tag=method.delivery_tag) channel.basic_consume(callback, queue='abc', # 队列名 no_ack=False) # 不通知已经收到,如果连接中断可能消息丢失 print(' [*] Waiting for message. To exit press CTRL+C') channel.start_consuming()
2、durable 消息不丢失
发数据的时候,就说了:我这条数据要持久化保存。
如果rabbitmq服务端机器如果挂掉了,会给这台机器做持久化。如果启动机器后,消息队列还在。
import pika # ############################## 生产者 ############################## credentials = pika.PlainCredentials('gaohui', 'gaohui') connection = pika.BlockingConnection(pika.ConnectionParameters( host='192.168.100.243',credentials=credentials)) channel = connection.channel() channel.queue_declare(queue='hello2',durable=True) # 如果队列没有创建,就创建这个队列 channel.basic_publish(exchange='', routing_key='hello2', # 指定队列的关键字为,这里是队列的名字 body='Hello World!', # 往队列里发的消息内容 properties=pika.BasicProperties( delivery_mode=2, )) print(" [x] Sent 'Hello World!'") connection.close()
import pika # ########################### 消费者 ########################### credentials = pika.PlainCredentials('gaohui', 'gaohui') # connection = pika.BlockingConnection(pika.ConnectionParameters(host=url_1, # credentials=credentials, ssl=ssl, port=port)) connection = pika.BlockingConnection(pika.ConnectionParameters( host='192.168.100.243',credentials=credentials)) channel = connection.channel() channel.queue_declare(queue='hello2',durable=True) # 如果队列没有创建,就创建这个队列 def callback(ch, method, propertities,body): print(" [x] Received %r" % body) import time time.sleep(10) print("ok") ch.basic_ack(delivery_tag=method.delivery_tag) channel.basic_consume(callback, queue='hello2', # 队列名 no_ack=False) # 不通知已经收到,如果连接中断可能消息丢失 print(' [*] Waiting for message. To exit press CTRL+C') channel.start_consuming()
测试:
1)把生产者.py执行三次。
2)然后在linux上停掉rabbitmq服务,然后再开启rabbitmq服务
3)运行:消费者.py:三条消息都打印了:
3、消息获取顺序
默认消息队列里的数据是按照顺序被消费者拿走,例如:消费者1 去队列中获取 奇数 序列的任务,消费者1去队列中获取 偶数 序列的任务。
因为默认是跳着取得。第一个消费者取得很快,已经执行到20了,但是第二个消费者只取到13,可能消息执行的顺序就有问题了。
如果多个消费者,如果不想跳着取,就按消息的顺序取,而不是按着自己的间隔了。
channel.basic_qos(prefetch_count=1) 表示谁来谁取,不再按照奇偶数排列
消费者:
import pika # ########################### 消费者 ########################### credentials = pika.PlainCredentials('gaohui', 'gaohui') # connection = pika.BlockingConnection(pika.ConnectionParameters(host=url_1, # credentials=credentials, ssl=ssl, port=port)) connection = pika.BlockingConnection(pika.ConnectionParameters( host='192.168.100.243',credentials=credentials)) channel = connection.channel() channel.queue_declare(queue='hello1') # 如果队列没有创建,就创建这个队列 def callback(ch, method, propertities,body): print(" [x] Received %r" % body) import time time.sleep(10) print("ok") ch.basic_ack(delivery_tag=method.delivery_tag) channel.basic_qos(prefetch_count=1) channel.basic_consume(callback, queue='hello1', # 队列名 no_ack=False) # 不通知已经收到,如果连接中断可能消息丢失 print(' [*] Waiting for message. To exit press CTRL+C') channel.start_consuming()
4、发布订阅
发布订阅原理:
1)发布订阅和简单的消息队列区别在于,发布订阅会将消息发送给所有的订阅者,而消息队列中的数据被消费一次便消失。
2)所以,RabbitMQ实现发布和订阅时,会为每一个订阅者创建一个队列,而发布者发布消息时,会将消息放置在所有相关队列中。
3)exchange 可以帮你发消息到多个队列!type设为什么值,就把消息发给哪些队列。
发布订阅应用到监控上:
模板就是写上一段脚本,放在服务器上,
客户端每5分钟,从服务端拿到监控模板,根据模板来取数据,
然后把数据结果发步到服务端的redis频道里。
服务端收到数据,1)处理历史记录 2)报警 3)dashboard显示监控信息
服务端有三处一直来订阅服务端频道(一直来收取客户端监控数据)
发布给所有绑定队列
exchange type = fanout
exchange 可以帮你发消息到多个队列,type = fanout表示:跟exchange绑定的所有队列,都会收到消息。

发布者:
import pika import sys # ############################## 发布者 ############################## credentials = pika.PlainCredentials('gaohui', 'gaohui') connection = pika.BlockingConnection(pika.ConnectionParameters( host='192.168.100.243',credentials=credentials)) channel = connection.channel() channel.exchange_declare(exchange="logs",type="fanout") # 如果队列没有创建,就创建这个队列 message = ' '.join(sys.argv[1:]) or "info: Hello World!" channel.basic_publish(exchange='logs', routing_key='', body=message) print(" [x] Sent %r" % message) connection.close()
订阅者:
import pika # ########################### 订阅者 ########################### credentials = pika.PlainCredentials('gaohui', 'gaohui') # connection = pika.BlockingConnection(pika.ConnectionParameters(host=url_1, # credentials=credentials, ssl=ssl, port=port)) connection = pika.BlockingConnection(pika.ConnectionParameters( host='192.168.100.243',credentials=credentials)) channel = connection.channel() channel.exchange_declare(exchange='logs', type='fanout') # 随机创建队列 result = channel.queue_declare(exclusive=True) queue_name = result.method.queue # 绑定 channel.queue_bind(exchange='logs', queue=queue_name) print(' [*] Waiting for logs. To exit press CTRL+C') def callback(ch, method, properties, body): print(" [x] %r" % body) channel.basic_consume(callback, queue=queue_name, no_ack=True) channel.start_consuming()
多次执行这个文件,就会随机生成多个队列。并且exchange都绑定这些队列。
然后发布者只需要给exchange发送消息,然后exchange绑定的多个队列都有这个消息了。订阅者就收到这个消息了。
5、关键字发送
发送消息时明确指定某个队列并向其中发送消息,RabbitMQ还支持根据关键字发送,即:队列绑定关键字,发送者将数据根据关键字发送到消息exchange,exchange根据 关键字 判定应该将数据发送至指定队列。

一个队列还可以绑定多个关键字
对一个随机队列,绑定三个关键字
再次执行,对另一个随机队列,只绑定一个关键字。
消费者:每执行一次可以生成一个队列。通过使用命令行传参的方式,来传入队列的关键字。
exchange type = direct
消费者:
import pika import sys connection = pika.BlockingConnection(pika.ConnectionParameters( host='localhost')) channel = connection.channel() channel.exchange_declare(exchange='direct_logs', type='direct') result = channel.queue_declare(exclusive=True) queue_name = result.method.queue severities = sys.argv[1:] if not severities: sys.stderr.write("Usage: %s [info] [warning] [error]\n" % sys.argv[0]) sys.exit(1) for severity in severities: channel.queue_bind(exchange='direct_logs', queue=queue_name, routing_key=severity) print(' [*] Waiting for logs. To exit press CTRL+C') def callback(ch, method, properties, body): print(" [x] %r:%r" % (method.routing_key, body)) channel.basic_consume(callback, queue=queue_name, no_ack=True) channel.start_consuming()
下面是测试:
消费者1:
import pika import sys # ########################### 订阅者 ########################### credentials = pika.PlainCredentials('gaohui', 'gaohui') # connection = pika.BlockingConnection(pika.ConnectionParameters(host=url_1, # credentials=credentials, ssl=ssl, port=port)) connection = pika.BlockingConnection(pika.ConnectionParameters( host='192.168.100.243',credentials=credentials)) channel = connection.channel() channel.exchange_declare(exchange='direct_logs', type='direct') result = channel.queue_declare(exclusive=True) # 随机生成队列 queue_name = result.method.queue severities = ["info", "warning", "error"] if not severities: sys.stderr.write("Usage: %s [info] [warning] [error]\n" % sys.argv[0]) sys.exit(1) for severity in severities: channel.queue_bind(exchange='direct_logs', queue=queue_name, routing_key=severity) print(' [*] Waiting for logs. To exit press CTRL+C') def callback(ch, method, properties, body): print(" [x] %r:%r" % (method.routing_key, body)) channel.basic_consume(callback, queue=queue_name, no_ack=True) channel.start_consuming()
消费者2:
import pika import sys # ########################### 订阅者 ########################### credentials = pika.PlainCredentials('gaohui', 'gaohui') # connection = pika.BlockingConnection(pika.ConnectionParameters(host=url_1, # credentials=credentials, ssl=ssl, port=port)) connection = pika.BlockingConnection(pika.ConnectionParameters( host='192.168.100.243',credentials=credentials)) channel = connection.channel() channel.exchange_declare(exchange='direct_logs', type='direct') result = channel.queue_declare(exclusive=True) # 随机生成队列 queue_name = result.method.queue severities = ["error"] for severity in severities: channel.queue_bind(exchange='direct_logs', queue=queue_name, routing_key=severity) print(' [*] Waiting for logs. To exit press CTRL+C') def callback(ch, method, properties, body): print(" [x] %r:%r" % (method.routing_key, body)) channel.basic_consume(callback, queue=queue_name, no_ack=True) channel.start_consuming()
生产者:
import pika import sys # ############################## 发布者 ############################## credentials = pika.PlainCredentials('gaohui', 'gaohui') connection = pika.BlockingConnection(pika.ConnectionParameters( host='192.168.100.243',credentials=credentials)) channel = connection.channel() channel.exchange_declare(exchange='direct_logs', type='direct') severity = 'info' message = 'Hello World!' channel.basic_publish(exchange='direct_logs', routing_key=severity, body=message) print(" [x] Sent %r:%r" % (severity, message)) connection.close()
同时运行消费者1,消费者2,然后修改生产者的关键字,运行生产者。
当生产者:severity = 'info',则消费者1收到消息,消费者2没收到消息
当生产者:severity = 'error',则消费者1、消费者2 都收到消息
6、模糊匹配

exchange type = topic
在topic类型下,可以让队列绑定几个模糊的关键字,之后发送者将数据发送到exchange,exchange将传入”路由值“和 ”关键字“进行匹配,匹配成功,则将数据发送到指定队列。
• # 表示可以匹配 0 个 或 多个 单词
• * 表示只能匹配 一个 单词
发送者路由值 队列中
old.boy.python old.* -- 不匹配
old.boy.python old.# -- 匹配
消费者:
import pika import sys # ########################### 订阅者 ########################### credentials = pika.PlainCredentials('gaohui', 'gaohui') # connection = pika.BlockingConnection(pika.ConnectionParameters(host=url_1, # credentials=credentials, ssl=ssl, port=port)) connection = pika.BlockingConnection(pika.ConnectionParameters( host='192.168.100.243',credentials=credentials)) channel = connection.channel() channel.exchange_declare(exchange='topic_logs', type='topic') result = channel.queue_declare(exclusive=True) queue_name = result.method.queue binding_keys = "*.orange.*" for binding_key in binding_keys: channel.queue_bind(exchange='topic_logs', queue=queue_name, routing_key=binding_key) print(' [*] Waiting for logs. To exit press CTRL+C') def callback(ch, method, properties, body): print(" [x] %r:%r" % (method.routing_key, body)) channel.basic_consume(callback, queue=queue_name, no_ack=True) channel.start_consuming()
生产者:
import pika import sys # ############################## 发布者 ############################## credentials = pika.PlainCredentials('gaohui', 'gaohui') connection = pika.BlockingConnection(pika.ConnectionParameters( host='192.168.100.243',credentials=credentials)) channel = connection.channel() channel.exchange_declare(exchange='topic_logs', type='topic') # routing_key = 'abc.new.qiaomei.old' routing_key = 'neworangeold' message = 'Hello World!' channel.basic_publish(exchange='topic_logs', routing_key=routing_key, body=message) print(" [x] Sent %r:%r" % (routing_key, message)) connection.close()
#.orange.# 匹配:new.orange.old ,不匹配: neworangeold
*.orange.* 匹配:neworangeold,不匹配:new.orange.old

浙公网安备 33010602011771号