Python之路day13:Redis、Memcache、SQLAlchemy
Memcached
Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态、数据库驱动网站的速度。Memcached基于一个存储键/值对的hashmap。其守护进程(daemon)是用C写的,但是客户端可以用任何语言来编写,并通过memcached协议与守护进程通信。
Memcached安装和基本使用
Memcached安装:
1 wget http://memcached.org/latest 2 tar -zxvf memcached-1.x.x.tar.gz 3 cd memcached-1.x.x 4 ./configure && make && make test && sudo make install 5 6 PS:依赖libevent 7 yum install libevent-devel 8 apt-get install libevent-dev
启动Memcached
1 memcached -d -m 10 -u root -l 10.211.55.4 -p 12000 -c 256 -P /tmp/memcached.pid 2 3 4 5 参数说明: 6 7 -d 是启动一个守护进程 8 9 -m 是分配给Memcache使用的内存数量,单位是MB 10 11 -u 是运行Memcache的用户 12 13 -l 是监听的服务器IP地址 14 15 -p 是设置Memcache监听的端口,最好是1024以上的端口 16 17 -c 选项是最大运行的并发连接数,默认是1024,按照你服务器的负载量来设定 18 19 -P 是设置保存Memcache的pid文件
Memcached命令
1 存储命令: set/add/replace/append/prepend/cas 2 3 获取命令: get/gets 4 5 其他命令: delete/stats..
Python操作Memcached
安装API
1 python操作Memcached使用Python-memcached模块 2 3 下载安装:https://pypi.python.org/pypi/python-memcached
1、第一次操作
1 import memcache 2 3 mc = memcache.Client(['10.211.55.4:12000'], debug=True) 4 mc.set("foo", "bar") 5 ret = mc.get('foo') 6 print(ret)
Ps: debug = True 表示运行出现错误时,显示错误信息,上线后移除该参数。
2、天生支持集群
python-memcached模块原生支持集群操作,其原理是在内存维护一个主机列表,且集群中主机的权重值和主机在列表中重复出现的次数成正比
1 主机 权重 2 1.1.1.1 1 3 1.1.1.2 2 4 1.1.1.3 1 5 那么在内存中主机列表为: 6 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"放置在改服务器的内存中
代码实现如下:
1 mc = memcache.Client([('1.1.1.1:12000', 1), ('1.1.1.2:12000', 2), ('1.1.1.3:12000', 1)], debug=True) 2 3 mc.set('k1', 'v1')
3、add
添加一条键值对,如果是已经存在的key,重复执行add操作会产生异常
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 import memcache 4 5 mc = memcache.Client(['10.211.55.4:12000'], debug=True) 6 mc.add('k1', 'v1') 7 # mc.add('k1', 'v2') # 报错,对已经存在的key重复添加,失败!!!
4、replace
replace 修改某个key的值,如果key不存在,则异常
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 import memcache 4 5 mc = memcache.Client(['10.211.55.4:12000'], debug=True) 6 # 如果memcache中存在kkkk,则替换成功,否则一场 7 mc.replace('kkkk','999')
5、set 和 set_multi
set 设置一个键值对,如果key不存在,则创建,如果key存在,则修改
set_multi 设置多个键值对,如果key不存在,则创建,如果key存在,则修改
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 import memcache 4 mc = memcache.Client(['10.211.55.4:12000'], debug=True) 5 6 mc.set('key0', 'wupeiqi') 7 8 mc.set_multi({'key1': 'val1', 'key2': 'val2'})
6、delete 和 delete_multi
delete 在Memcached中删除指定的一个键值对
delete_multi 在Memcached中删除指定的多个键值对
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 import memcache 4 mc = memcache.Client(['10.211.55.4:12000'], debug=True) 5 6 mc.delete('key0') 7 8 mc.delete_multi(['key1', 'key2'])
7、get 和 get_multi
get 获取一个键值对
get_multi 获取多个键值对
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 import memcache 4 mc = memcache.Client(['10.211.55.4:12000'], debug=True) 5 6 val = mc.get('key0') 7 8 item_dict = mc.get_multi(["key1", "key2", "key3"])
8、append和 prepend
append 修改指定key的值,在该值 后面 追加内容
prepend 修改指定key的值,在该值 前面 插入内容
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 import memcache 4 mc = memcache.Client(['10.211.55.4:12000'], debug=True) 5 # k1 = "v1" 6 7 mc.append('k1', 'after') 8 # k1 = "v1after" 9 10 mc.prepend('k1', 'before') 11 # k1 = "beforev1after"
9、decr和 incr
incr 自增,将Memcached中的某一个值增加N (N默认为1)
decr 自减,将Memcached中的某一个值减少N (N默认为1)
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 import memcache 4 5 mc = memcache.Client(['10.211.55.4:12000'], debug=True) 6 mc.set('k1', '777') 7 8 mc.incr('k1') 9 # k1 = 778 10 11 mc.incr('k1', 10) 12 # k1 = 788 13 14 mc.decr('k1') 15 # k1 = 787 16 17 mc.decr('k1', 10) 18 # 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 即可,如:
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 import memcache 4 mc = memcache.Client(['10.211.55.4:12000'], debug=True, cache_cas=True) 5 6 v = mc.gets('product_count') 7 # ... 8 # 如果有人在gets之后和cas之前修改了product_count,那么,下面的设置将会执行失败,剖出异常,从而避免非正常数据的产生 9 mc.cas('product_count', "899")
Ps:本质上每次执行gets时,会从memcaache中获取一个自增的数字,通过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(主从)同步。
Redis安装和基本使用
1 wget http://download.redis.io/releases/redis-3.0.6.tar.gz 2 tar xzf redis-3.0.6.tar.gz 3 cd redis-3.0.6 4 make 5 6 启动服务端 7 src/redis-server 8 9 启动客户端 10 src/redis-cli 11 redis> set foo bar 12 OK 13 redis> get foo 14 "bar"
Python操作Redis
1 sudo pip install redis 2 or 3 sudo easy_install redis 4 or 5 源码安装 6 7 详见:https://github.com/WoLpH/redis-py
API使用
redis-py的API的使用可以分类为:
• 连接方式
• 连接池
• 操作
• String 操作
• Hash 操作
• List 操作
• Set 操作
• Sort Set 操作
• 管道
• 发布订阅
1、操作模式
redis-py提供两个类Redis和StrictRedis用于实现Redis的命令,StrictRedis用于实现大部分官方的命令,并使用官方的语法和命令,Redis是StrictRedis的子类,用于向后兼容旧版本的redis-py。
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 import redis 4 5 r = redis.Redis(host='10.211.55.4', port=6379) 6 r.set('foo', 'Bar') 7 print r.get('foo')
2、连接池
redis-py使用connection poll来管理对一个redis server的所有连接,避免每次建立、释放连接的开销。默认,每个Redis实例都会维护一个自己的连接池。可以直接建立一个连接池,然后作为参数Redis,这样就可以实现多个Redis实例共享一个连接池。
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 import redis 4 5 pool = redis.ConnectionPool(host='10.211.55.4', port=6379) 6 7 r = redis.Redis(connection_pool=pool) 8 r.set('foo', 'Bar') 9 print r.get('foo')
3、操作
String操作,redis中的String在内存中按照一个name对应一个value来存储。如图:

1 set(name, value, ex=None, px=None, nx=False, xx=False) 2 在Redis中设置值,默认,不存在则创建,存在则修改 3 参数: 4 ex,过期时间(秒) 5 px,过期时间(毫秒) 6 nx,如果设置为True,则只有name不存在时,当前set操作才执行 7 xx,如果设置为True,则只有name存在时,岗前set操作才执行 8 9 10 setnx(name, value) 11 设置值,只有name不存在时,执行设置操作(添加) 12 13 setex(name, value, time) 14 # 设置值 15 # 参数: 16 # time,过期时间(数字秒 或 timedelta对象) 17 18 psetex(name, time_ms, value) 19 # 设置值 20 # 参数: 21 # time_ms,过期时间(数字毫秒 或 timedelta对象) 22 23 mset(*args, **kwargs) 24 批量设置值 25 如: 26 mset(k1='v1', k2='v2') 27 或 28 mget({'k1': 'v1', 'k2': 'v2'}) 29 30 get(name) 31 获取值 32 33 mget(keys, *args) 34 批量获取 35 如: 36 mget('ylr', 'wupeiqi') 37 或 38 r.mget(['ylr', 'wupeiqi']) 39 40 getset(name, value) 41 设置新值并获取原来的值 42 43 getrange(key, start, end) 44 # 获取子序列(根据字节获取,非字符) 45 # 参数: 46 # name,Redis 的 name 47 # start,起始位置(字节) 48 # end,结束位置(字节) 49 # 如: "武沛齐" ,0-3表示 "武" 50 51 setrange(name, offset, value) 52 # 修改字符串内容,从指定字符串索引开始向后替换(新值太长时,则向后添加) 53 # 参数: 54 # offset,字符串的索引,字节(一个汉字三个字节) 55 # value,要设置的值 56 57 setbit(name, offset, value) 58 # 对name对应值的二进制表示的位进行操作 59 60 # 参数: 61 # name,redis的name 62 # offset,位的索引(将值变换成二进制后再进行索引) 63 # value,值只能是 1 或 0 64 65 # 注:如果在Redis中有一个对应: n1 = "foo", 66 那么字符串foo的二进制表示为:01100110 01101111 01101111 67 所以,如果执行 setbit('n1', 7, 1),则就会将第7位设置为1, 68 那么最终二进制则变成 01100111 01101111 01101111,即:"goo" 69 70 # 扩展,转换二进制表示: 71 # source = "武沛齐" 72 source = "foo" 73 74 for i in source: 75 num = ord(i) 76 print bin(num).replace('b','') 77 78 特别的,如果source是汉字 "武沛齐"怎么办? 79 答:对于utf-8,每一个汉字占 3 个字节,那么 "武沛齐" 则有 9个字节 80 对于汉字,for循环时候会按照 字节 迭代,那么在迭代时,将每一个字节转换 十进制数,然后再将十进制数转换成二进制 81 11100110 10101101 10100110 11100110 10110010 10011011 11101001 10111101 10010000 82 -------------------------- ----------------------------- ----------------------------- 83 武 沛 齐 84 85 getbit(name, offset) 86 # 获取name对应的值的二进制表示中的某位的值 (0或1) 87 88 bitcount(key, start=None, end=None) 89 # 获取name对应的值的二进制表示中 1 的个数 90 # 参数: 91 # key,Redis的name 92 # start,位起始位置 93 # end,位结束位置 94 95 bitop(operation, dest, *keys) 96 # 获取多个值,并将值做位运算,将最后的结果保存至新的name对应的值 97 98 # 参数: 99 # operation,AND(并) 、 OR(或) 、 NOT(非) 、 XOR(异或) 100 # dest, 新的Redis的name 101 # *keys,要查找的Redis的name 102 103 # 如: 104 bitop("AND", 'new_name', 'n1', 'n2', 'n3') 105 # 获取Redis中n1,n2,n3对应的值,然后讲所有的值做位运算(求并集),然后将结果保存 new_name 对应的值中 106 107 strlen(name) 108 # 返回name对应值的字节长度(一个汉字3个字节) 109 110 incr(self, name, amount=1) 111 # 自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。 112 113 # 参数: 114 # name,Redis的name 115 # amount,自增数(必须是整数) 116 117 # 注:同incrby 118 119 incrbyfloat(self, name, amount=1.0) 120 # 自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。 121 122 # 参数: 123 # name,Redis的name 124 # amount,自增数(浮点型) 125 126 decr(self, name, amount=1) 127 # 自减 name对应的值,当name不存在时,则创建name=amount,否则,则自减。 128 129 # 参数: 130 # name,Redis的name 131 # amount,自减数(整数) 132 133 append(key, value) 134 # 在redis name对应的值后面追加内容 135 136 # 参数: 137 key, redis的name 138 value, 要追加的字符串
Hash操作,redis中Hash在内存中的存储格式如下图:

1 hset(name, key, value) 2 # name对应的hash中设置一个键值对(不存在,则创建;否则,修改) 3 4 # 参数: 5 # name,redis的name 6 # key,name对应的hash中的key 7 # value,name对应的hash中的value 8 9 # 注: 10 # hsetnx(name, key, value),当name对应的hash中不存在当前key时则创建(相当于添加) 11 12 hmset(name, mapping) 13 # 在name对应的hash中批量设置键值对 14 15 # 参数: 16 # name,redis的name 17 # mapping,字典,如:{'k1':'v1', 'k2': 'v2'} 18 19 # 如: 20 # r.hmset('xx', {'k1':'v1', 'k2': 'v2'}) 21 22 hget(name,key) 23 # 在name对应的hash中获取根据key获取value 24 25 hmget(name, keys, *args) 26 # 在name对应的hash中获取多个key的值 27 28 # 参数: 29 # name,reids对应的name 30 # keys,要获取key集合,如:['k1', 'k2', 'k3'] 31 # *args,要获取的key,如:k1,k2,k3 32 33 # 如: 34 # r.mget('xx', ['k1', 'k2']) 35 # 或 36 # print r.hmget('xx', 'k1', 'k2') 37 38 hgetall(name) 39 获取name对应hash的所有键值 40 41 hlen(name) 42 # 获取name对应的hash中键值对的个数 43 44 hkeys(name) 45 # 获取name对应的hash中所有的key的值 46 47 hvals(name) 48 # 获取name对应的hash中所有的value的值 49 50 hexists(name, key) 51 # 检查name对应的hash是否存在当前传入的key 52 53 hdel(name,*keys) 54 # 将name对应的hash中指定key的键值对删除 55 56 hincrby(name, key, amount=1) 57 # 自增name对应的hash中的指定key的值,不存在则创建key=amount 58 # 参数: 59 # name,redis中的name 60 # key, hash对应的key 61 # amount,自增数(整数) 62 63 hincrbyfloat(name, key, amount=1.0) 64 # 自增name对应的hash中的指定key的值,不存在则创建key=amount 65 66 # 参数: 67 # name,redis中的name 68 # key, hash对应的key 69 # amount,自增数(浮点数) 70 71 # 自增name对应的hash中的指定key的值,不存在则创建key=amount 72 73 hscan(name, cursor=0, match=None, count=None) 74 # 增量式迭代获取,对于数据大的数据非常有用,hscan可以实现分片的获取数据,并非一次性将数据全部获取完,从而放置内存被撑爆 75 76 # 参数: 77 # name,redis的name 78 # cursor,游标(基于游标分批取获取数据) 79 # match,匹配指定key,默认None 表示所有的key 80 # count,每次分片最少获取个数,默认None表示采用Redis的默认分片个数 81 82 # 如: 83 # 第一次:cursor1, data1 = r.hscan('xx', cursor=0, match=None, count=None) 84 # 第二次:cursor2, data1 = r.hscan('xx', cursor=cursor1, match=None, count=None) 85 # ... 86 # 直到返回值cursor的值为0时,表示数据已经通过分片获取完毕 87 88 hscan_iter(name, match=None, count=None) 89 # 利用yield封装hscan创建生成器,实现分批去redis中获取数据 90 91 # 参数: 92 # match,匹配指定key,默认None 表示所有的key 93 # count,每次分片最少获取个数,默认None表示采用Redis的默认分片个数 94 95 # 如: 96 # for item in r.hscan_iter('xx'): 97 # print item
List操作,redis中的List在内存中按照一个name对应一个List来存储。如图:

1 lpush(name,values) 2 # 在name对应的list中添加元素,每个新的元素都添加到列表的最左边 3 4 # 如: 5 # r.lpush('oo', 11,22,33) 6 # 保存顺序为: 33,22,11 7 8 # 扩展: 9 # rpush(name, values) 表示从右向左操作 10 11 lpushx(name,value) 12 # 在name对应的list中添加元素,只有name已经存在时,值添加到列表的最左边 13 14 # 更多: 15 # rpushx(name, value) 表示从右向左操作 16 17 llen(name) 18 # name对应的list元素的个数 19 20 linsert(name, where, refvalue, value)) 21 # 在name对应的列表的某一个值前或后插入一个新值 22 23 # 参数: 24 # name,redis的name 25 # where,BEFORE或AFTER 26 # refvalue,标杆值,即:在它前后插入数据 27 # value,要插入的数据 28 29 r.lset(name, index, value) 30 # 对name对应的list中的某一个索引位置重新赋值 31 32 # 参数: 33 # name,redis的name 34 # index,list的索引位置 35 # value,要设置的值 36 37 r.lrem(name, value, num) 38 # 在name对应的list中删除指定的值 39 40 # 参数: 41 # name,redis的name 42 # value,要删除的值 43 # num, num=0,删除列表中所有的指定值; 44 # num=2,从前到后,删除2个; 45 # num=-2,从后向前,删除2个 46 47 lpop(name) 48 # 在name对应的列表的左侧获取第一个元素并在列表中移除,返回值则是第一个元素 49 50 # 更多: 51 # rpop(name) 表示从右向左操作 52 53 lindex(name, index) 54 在name对应的列表中根据索引获取列表元素 55 56 lrange(name, start, end) 57 # 在name对应的列表分片获取数据 58 # 参数: 59 # name,redis的name 60 # start,索引的起始位置 61 # end,索引结束位置 62 63 ltrim(name, start, end) 64 # 在name对应的列表中移除没有在start-end索引之间的值 65 # 参数: 66 # name,redis的name 67 # start,索引的起始位置 68 # end,索引结束位置 69 70 rpoplpush(src, dst) 71 # 从一个列表取出最右边的元素,同时将其添加至另一个列表的最左边 72 # 参数: 73 # src,要取数据的列表的name 74 # dst,要添加数据的列表的name 75 76 blpop(keys, timeout) 77 # 将多个列表排列,按照从左到右去pop对应列表的元素 78 79 # 参数: 80 # keys,redis的name的集合 81 # timeout,超时时间,当元素所有列表的元素获取完之后,阻塞等待列表内有数据的时间(秒), 0 表示永远阻塞 82 83 # 更多: 84 # r.brpop(keys, timeout),从右向左获取数据 85 86 brpoplpush(src, dst, timeout=0) 87 # 从一个列表的右侧移除一个元素并将其添加到另一个列表的左侧 88 89 # 参数: 90 # src,取出并要移除元素的列表对应的name 91 # dst,要插入元素的列表对应的name 92 # timeout,当src对应的列表中没有数据时,阻塞等待其有数据的超时时间(秒),0 表示永远阻塞 93 94 自定义增量迭代 95 # 由于redis类库中没有提供对列表元素的增量迭代,如果想要循环name对应的列表的所有元素,那么就需要: 96 # 1、获取name对应的所有列表 97 # 2、循环列表 98 # 但是,如果列表非常大,那么就有可能在第一步时就将程序的内容撑爆,所有有必要自定义一个增量迭代的功能: 99 100 def list_iter(name): 101 """ 102 自定义redis列表增量迭代 103 :param name: redis中的name,即:迭代name对应的列表 104 :return: yield 返回 列表元素 105 """ 106 list_count = r.llen(name) 107 for index in xrange(list_count): 108 yield r.lindex(name, index) 109 110 # 使用 111 for item in list_iter('pp'): 112 print(item)113 114 Set操作,Set集合就是不允许重复的列表 115 sadd(name,values) 116 117 # name对应的集合中添加元素 118 119 scard(name) 120 获取name对应的集合中元素个数 121 122 sdiff(keys, *args) 123 在第一个name对应的集合中且不在其他name对应的集合的元素集合 124 125 sdiffstore(dest, keys, *args) 126 # 获取第一个name对应的集合中且不在其他name对应的集合,再将其新加入到dest对应的集合中 127 128 sinter(keys, *args) 129 # 获取多一个name对应集合的并集 130 131 sinterstore(dest, keys, *args) 132 # 获取多一个name对应集合的并集,再讲其加入到dest对应的集合中 133 134 sismember(name, value) 135 # 检查value是否是name对应的集合的成员 136 137 smembers(name) 138 # 获取name对应的集合的所有成员 139 140 smove(src, dst, value) 141 # 将某个成员从一个集合中移动到另外一个集合 142 143 spop(name) 144 # 从集合的右侧(尾部)移除一个成员,并将其返回 145 146 srandmember(name, numbers) 147 # 从name对应的集合中随机获取 numbers 个元素 148 149 srem(name, values) 150 # 在name对应的集合中删除某些值 151 152 sunion(keys, *args) 153 # 获取多一个name对应的集合的并集 154 155 sunionstore(dest,keys, *args) 156 # 获取多一个name对应的集合的并集,并将结果保存到dest对应的集合中 157 158 sscan(name, cursor=0, match=None, count=None) 159 sscan_iter(name, match=None, count=None) 160 # 同字符串的操作,用于增量迭代分批获取元素,避免内存消耗太大
有序集合,在集合的基础上,为每个元素排序;元素的排序需要根据另外一个值进行比较,所以,对于有序集合,每一个元素有两个值,即:值和分数,分数专门用来做排序。
1 zadd(name, *args, **kwargs) 2 # 在name对应的有序集合中添加元素 3 # 如: 4 # zadd('zz', 'n1', 1, 'n2', 2) 5 # 或 6 # zadd('zz', n1=11, n2=22) 7 8 zcard(name) 9 # 获取name对应的有序集合元素的数量 10 11 zcount(name, min, max) 12 # 获取name对应的有序集合中分数 在 [min,max] 之间的个数 13 14 zincrby(name, value, amount) 15 # 自增name对应的有序集合的 name 对应的分数 16 17 r.zrange( name, start, end, desc=False, withscores=False, score_cast_func=float) 18 # 按照索引范围获取name对应的有序集合的元素 19 20 # 参数: 21 # name,redis的name 22 # start,有序集合索引起始位置(非分数) 23 # end,有序集合索引结束位置(非分数) 24 # desc,排序规则,默认按照分数从小到大排序 25 # withscores,是否获取元素的分数,默认只获取元素的值 26 # score_cast_func,对分数进行数据转换的函数 27 28 # 更多: 29 # 从大到小排序 30 # zrevrange(name, start, end, withscores=False, score_cast_func=float) 31 32 # 按照分数范围获取name对应的有序集合的元素 33 # zrangebyscore(name, min, max, start=None, num=None, withscores=False, score_cast_func=float) 34 # 从大到小排序 35 # zrevrangebyscore(name, max, min, start=None, num=None, withscores=False, score_cast_func=float) 36 37 zrank(name, value) 38 # 获取某个值在 name对应的有序集合中的排行(从 0 开始) 39 40 # 更多: 41 # zrevrank(name, value),从大到小排序 42 43 zrangebylex(name, min, max, start=None, num=None) 44 # 当有序集合的所有成员都具有相同的分值时,有序集合的元素会根据成员的 值 (lexicographical ordering)来进行排序,而这个命令则可以返回给定的有序集合键 key 中, 元素的值介于 min 和 max 之间的成员 45 # 对集合中的每个成员进行逐个字节的对比(byte-by-byte compare), 并按照从低到高的顺序, 返回排序后的集合成员。 如果两个字符串有一部分内容是相同的话, 那么命令会认为较长的字符串比较短的字符串要大 46 47 # 参数: 48 # name,redis的name 49 # min,左区间(值)。 + 表示正无限; - 表示负无限; ( 表示开区间; [ 则表示闭区间 50 # min,右区间(值) 51 # start,对结果进行分片处理,索引位置 52 # num,对结果进行分片处理,索引后面的num个元素 53 54 # 如: 55 # ZADD myzset 0 aa 0 ba 0 ca 0 da 0 ea 0 fa 0 ga 56 # r.zrangebylex('myzset', "-", "[ca") 结果为:['aa', 'ba', 'ca'] 57 58 # 更多: 59 # 从大到小排序 60 # zrevrangebylex(name, max, min, start=None, num=None) 61 62 zrem(name, values) 63 # 删除name对应的有序集合中值是values的成员 64 65 # 如:zrem('zz', ['s1', 's2']) 66 67 zremrangebyrank(name, min, max) 68 # 根据排行范围删除 69 70 zremrangebyscore(name, min, max) 71 # 根据分数范围删除 72 73 zremrangebylex(name, min, max) 74 # 根据值返回删除 75 76 zscore(name, value) 77 # 获取name对应有序集合中 value 对应的分数 78 79 zinterstore(dest, keys, aggregate=None) 80 # 获取两个有序集合的交集,如果遇到相同值不同分数,则按照aggregate进行操作 81 # aggregate的值为: SUM MIN MAX 82 83 zunionstore(dest, keys, aggregate=None) 84 # 获取两个有序集合的并集,如果遇到相同值不同分数,则按照aggregate进行操作 85 # aggregate的值为: SUM MIN MAX 86 87 zscan(name, cursor=0, match=None, count=None, score_cast_func=float) 88 zscan_iter(name, match=None, count=None,score_cast_func=float) 89 90 # 同字符串相似,相较于字符串新增score_cast_func,用来对分数进行操作
其他常用操作
1 delete(*names) 2 # 根据删除redis中的任意数据类型 3 4 exists(name) 5 # 检测redis的name是否存在 6 7 keys(pattern='*') 8 # 根据模型获取redis的name 9 10 # 更多: 11 # KEYS * 匹配数据库中所有 key 。 12 # KEYS h?llo 匹配 hello , hallo 和 hxllo 等。 13 # KEYS h*llo 匹配 hllo 和 heeeeello 等。 14 # KEYS h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo 15 16 expire(name ,time) 17 # 为某个redis的某个name设置超时时间 18 19 rename(src, dst) 20 # 对redis的name重命名为 21 22 move(name, db)) 23 # 将redis的某个值移动到指定的db下 24 25 randomkey() 26 # 随机获取一个redis的name(不删除) 27 28 type(name) 29 # 获取name对应值的类型 30 31 scan(cursor=0, match=None, count=None) 32 scan_iter(match=None, count=None) 33 34 # 同字符串操作,用于增量迭代获取key
4、管道
redis-py默认在执行每次请求都会创建(连接池申请连接)和断开(归还连接池)一次连接操作,如果想要在一次请求中指定多个命令,则可以使用pipeline实现一次请求指定多个命令,并且默认情况下一次pipeline是原子性操作。
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 import redis 4 5 pool = redis.ConnectionPool(host='10.211.55.4', port=6379) 6 7 r = redis.Redis(connection_pool=pool) 8 9 # pipe = r.pipeline(transaction=False) 10 pipe = r.pipeline(transaction=True) 11 12 pipe.set('name', 'alex') 13 14 pipe.set('role', 'sb') 15 16 pipe.execute()
5、发布订阅

发布者:服务器
订阅者:Dashboad和数据处理
Demo如下:
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 import redis 4 5 class RedisHelper: 6 def __init__(self): 7 self.__conn = redis.Redis(host='10.211.55.4') 8 self.chan_sub = 'fm104.5' 9 self.chan_pub = 'fm104.5' 10 11 def public(self, msg): 12 self.__conn.publish(self.chan_pub, msg) 13 return True 14 15 def subscribe(self): 16 pub = self.__conn.pubsub() 17 pub.subscribe(self.chan_sub) 18 pub.parse_response() 19 return pub
订阅者:
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 from monitor.RedisHelper import RedisHelper 5 6 obj = RedisHelper() 7 redis_sub = obj.subscribe() 8 9 while True: 10 msg= redis_sub.parse_response() 11 print(msg)
发布者:
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from monitor.RedisHelper import RedisHelper 4 5 obj = RedisHelper() 6 obj.public('hello')
SQLAlchemy
SQLAlchemy是Python编程语言下的一款ORM框架,该框架建立在数据库API之上,使用关系对象映射进行数据库操作,简而言之是:将对象转换成SQL,然后使用数据API执行SQL并获取执行结果。

Dialect用于和数据API进行交流,根据配置文件的不同调用不同的数据库API,从而实现对数据库的操作,如:
1 MySQL-Python 2 mysql+mysqldb://<user>:<password>@<host>[:<port>]/<dbname> 3 4 pymysql 5 mysql+pymysql://<username>:<password>@<host>/<dbname>[?<options>] 6 7 MySQL-Connector 8 mysql+mysqlconnector://<user>:<password>@<host>[:<port>]/<dbname> 9 10 cx_Oracle 11 oracle+cx_oracle://user:pass@host:port/dbname[?key=value&key=value...] 12 13 更多详见:http://docs.sqlalchemy.org/en/latest/dialects/index.html
步骤一:
使用 Engine/ConnectionPooling/Dialect 进行数据库操作,Engine使用ConnectionPooling连接数据库,然后在通过Dialect执行SQL语句。
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from sqlalchemy import create_engine 4 5 engine = create_engine("mysql+mysqldb://root:123@127.0.0.1:3306/s11", max_overflow=5) 6 7 engine.execute( 8 "INSERT INTO ts_test (a, b) VALUES ('2', 'v1')" 9 ) 10 11 engine.execute( 12 "INSERT INTO ts_test (a, b) VALUES (%s, %s)", 13 ((555, "v1"),(666, "v1"),) 14 ) 15 engine.execute( 16 "INSERT INTO ts_test (a, b) VALUES (%(id)s, %(name)s)", 17 id=999, name="v1" 18 ) 19 20 result = engine.execute('select * from ts_test') 21 result.fetchall()
步骤二:
使用 Schema Type/SQL Expression Language/Engine/ConnectionPooling/Dialect 进行数据库操作。Engine使用Schema Type创建一个特定的结构对象,之后通过SQL Expression Language将该对象转换成SQL语句,然后通过ConnectionPooling连接数据库,再通过Dialect 执行SQL,并获取结果。
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 from sqlalchemy import create_engine, Table, Column, Integer, String, MetaData, ForeignKey 5 6 metadata = MetaData() 7 8 user = Table('user', metadata, 9 Column('id', Integer, primary_key=True), 10 Column('name', String(20)), 11 ) 12 13 color = Table('color', metadata, 14 Column('id', Integer, primary_key=True), 15 Column('name', String(20)), 16 ) 17 engine = create_engine("mysql+mysqldb://root:123@127.0.0.1:3306/s11", max_overflow=5) 18 19 metadata.create_all(engine) 20 # metadata.clear() 21 # metadata.remove()
注:SQLAlchemy无法修改表结构,如果需要可以使用SQLAlchemy开发者开源的另外一个软件Alembic来完成。
步骤三:
使用 ORM/Schema Type/SQL Expression Language/Engine/connectionPooling/Dialect 所有组件对数据库进行操作。根据类创建对象,对象转换成SQL,执行SQL。
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from sqlalchemy.ext.declarative import declarative_base 4 from sqlalchemy import Column, Integer, String 5 from sqlalchemy.orm import sessionmaker 6 from sqlalchemy import create_engine 7 8 engine = create_engine("mysql+mysqldb://root:123@127.0.0.1:3306/s11", max_overflow=5) 9 10 Base = declarative_base() 11 12 class User(Base): 13 __tablename__ = 'users' 14 id = Column(Integer, primary_key=True) 15 name = Column(String(50)) 16 17 # 寻找Base的所有子类,按照子类的结构在数据库中生成对应的数据表信息 18 # Base.metadata.create_all(engine) 19 Session = sessionmaker(bind=engine) 20 session = Session() 21 22 # ########## 增 ########## 23 # u = User(id=2, name='sb') 24 # session.add(u) 25 # session.add_all([ 26 # User(id=3, name='sb'), 27 # User(id=4, name='sb') 28 # ]) 29 # session.commit() 30 31 # ########## 删除 ########## 32 # session.query(User).filter(User.id > 2).delete() 33 # session.commit() 34 35 # ########## 修改 ########## 36 # session.query(User).filter(User.id > 2).update({'cluster_id' : 0}) 37 # session.commit() 38 39 # ########## 查 ########## 40 # ret = session.query(User).filter_by(name='sb').first() 41 # ret = session.query(User).filter_by(name='sb').all() 42 # print ret 43 44 # ret = session.query(User).filter(User.name.in_(['sb','bb'])).all() 45 # print ret 46 47 # ret = session.query(User.name.label('name_label')).all() 48 # print ret,type(ret) 49 50 # ret = session.query(User).order_by(User.id).all() 51 # print ret 52 53 # ret = session.query(User).order_by(User.id)[1:3] 54 # print ret 55 # session.commit()
更多内容请参考:http://www.cnblogs.com/wupeiqi/articles/5132791.html
自己的代码

浙公网安备 33010602011771号