一、redis简介
Redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。 Redis的出现,很大程度补偿了memcached这类key/value存储的不足,在部分场合可以对关系数据库起到很好的补充作用。它提供了Python,Ruby,Erlang,PHP客户端,使用很方便,并且Redis还支持主从同步。数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从服务器的主服务器。这使得Redis可执行单层树复制。从盘可以有意无意的对数据进行写操作。由于完全实现了发布/订阅机制,使得从数据库在任何地方同步树时,可订阅一个频道并接收主服务器完整的消息发布记录。
二、redis使用
1、redis安装
3.0版本
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#cd /usr/local/src #wget http://download.redis.io/releases/redis-3.0.1.tar.gz #tar xzf redis-3.0.1.tar.gz #cd redis-3.0.1 #make #src/redis-server & 检查redis是否正常启动 Ps –ef |grep redis Netstat –lnp |grep 6379
2.8版本
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
yum install -y epel-release yum install -y gcc jemalloc-devel wget cd /usr/local/src wget https://codeload.github.com/antirez/redis/tar.gz/2.8.21 -O redis-2.8.21.tar.gz tar xf redis-2.8.21.tar.gz cd redis-2.8.21 make make PREFIX=/usr/local/redis install mkdir /usr/local/redis/etc wget http://www.apelearn.com/study_v2/.redis_conf -O /usr/local/redis/etc/redis.conf 2>/dev/null # 下载配置文件 wget http://www.apelearn.com/study_v2/.redis_init -O /etc/init.d/redis 2>/dev/null # 下载启动脚本 useradd -s /sbin/nologin redis mkdir /usr/local/redis/var chmod 777 /usr/local/redis/var chmod 755 /etc/init.d/redis chkconfig --add redis chkconfig redis on /etc/init.d/redis start
安装redis的客户端
Pip install redis
配置主从
只需要在从的配置文件上加 slavof 主(ip) 6379(端口)
客户端连接
/usr/local/redis/bin/redis-cli
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
[root@localhost ~]# /usr/local/redis/bin/redis-cli // 连接Redis 127.0.0.1:6379> keys * // keys 用于查看所有key,也可以模糊匹配,如 keys my* 127.0.0.1:6379> exists name // exists 用于判断是否有某个key,有返回1,没有返回0 127.0.0.1:6379> del name // del 用于删除指定的key,成功返回1,失败返回0 127.0.0.1:6379> expire name 100 // expire 用于设置指定的key多长时间后过期,单位为秒 127.0.0.1:6379> persist name // persist 用于取消指定key的过期时间 127.0.0.1:6379> ttl name // ttl 用于查看指定的key还有多长时间过期,返回-2表示没有该key,返回-1表示没有设置过期时间,其他表示还有多长时间过期 127.0.0.1:6379> select 0 // select 用于选择哪个库 127.0.0.1:6379> move name 2 // move 用于把指定的key移到哪个库下 127.0.0.1:6379> randomkey // randomkey 用于随机返回一个key 127.0.0.1:6379> rename k1 k2 // rename 用于重命名key 127.0.0.1:6379> type name // type 用于查看指定key的类型 127.0.0.1:6379> dbsize // dbsize 用于返回当前数据库中key的数目 127.0.0.1:6379> info // info 用于返回redis数据库的状态信息 127.0.0.1:6379> flushdb // flushdb 用于清空当前数据库中的所有key 127.0.0.1:6379> flushall // flushall 用于清空所有数据库中的所有key
安装redis模块
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
cd /usr/local/src wget --no-check-certificate https://pypi.python.org/packages/source/r/redis/redis-2.8.0.tar.gz tar xf redis-2.8.0.tar.gz mv redis-2.8.0 python-redis-2.8.0 cd python-redis-2.8.0/ python setup.py install
Python 连接并操作 redis
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import redis r = redis.Redis(host="192.168.214.22", port=6379) r.set("jim", "I love you!") print(r.get("jim")) print(r.keys()) # print(dir(r)) 结果: I love you! ['jim', 'ajing']
连接池
Redis对象使用connection pool来管理对一个redis server的所有连接,避免每次建立、释放连接的开销。默认,每个Redis实例都会维护一个自己的连接池。可以直接建立一个连接池,然后作为参数Redis,这样就可以实现多个Redis实例共享一个连接池。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import redis pool = redis.ConnectionPool(host="192.168.214.22") # redis.ConnectionPool() 用于创建一个连接池 r = redis.Redis(connection_pool=pool) # 通过 redis.Redis() 连接到连接池 r.set("name", "jim") # 执行 redis 操作 print(r.get("name"))
管道pipline
Redis是一个cs模式的tcp server,使用和http类似的请求响应协议。一个client可以通过一个socket连接发起多个请求命令。每个请求命令发出后client通常会阻塞并等待redis服务处理,redis处理完后请求命令后会将结果通过响应报文返回给client。基本的通信过程如下
import redis pool = redis.ConnectionPool(host='10.0.0.3',port='6379',db=0) r = redis.Redis(connection_pool=pool) pipline = r.pipeline(transaction=True) pipline.set('hobby','girl') pipline.set('hobby','girl') pipline.set('hobby','girl') pipline.set('hobby','girl') pipline.set('hobby','girl') pipline.execute() # 利用redis对象的pipline创建pipline对象 # 利用pipeline对象执行set命令 # 利用pipline对象的execute函数批量执行
理解:pipline对象就是一个容器,我们把要执行的语句放入其中,调用其excute函数去批量执行。
注意:在get请求的时候,执行pipe.exceute(),会批量返回,但是是有序的,我们可以定义多个变量去接受
import redis pool = redis.ConnectionPool(host='10.0.0.3',port='6379',db=0) r = redis.Redis(connection_pool=pool) pipline = r.pipeline(transaction=True) pipline.get('name') pipline.get('age') pipline.get('job') pipline.get('hobby') name,age,job,hobby = pipline.execute() # 定义4个变量接受 print(name,age,job,hobby)
string操作
1、set 设置值,不存在创建,存在则更新。
import redis pool = redis.ConnectionPool(host='10.0.0.3',port='6379',db=0) r = redis.Redis(connection_pool=pool) r.set(name, value, ex=None, px=None, nx=False, xx=False) # name 表示key的名称 # value 表示对应的值 # ex 过期时间(秒) # px 过期时间(毫秒) # nx 如果设置为True,则只有name不存在时,当前set操作才执行,同setnx(name, value) # xx 如果设置为True,则只有name存在时,当前set操作才执行
PS:针对过期时间还可以用另外两个函数进行单独调整
setex(name, value, time) #设置过期时间(秒) psetex(name, time_ms, value) #设置过期时间(豪秒)
2、mset 批量设置值,是set的升级款
r.mset(name='bigk', age='18') r.mset({"name":'bigk', "age":'18'}) # mset接受 *args和 **kwargs。 # 所以只能传递dict 或者 命名关键词参数,否则会报RedisError异常
3、get/mget 获取/批量获取key值
r.get(name) r.mget(name1,name2) # get函数只有一个参数:key名称 # mget可以列举多个key名称,或者传递一个list li = ['name','age'] print(r.mget(li))
4、getset 设置新值,打印原值
r.getset(name,value) print(r.getset('name','dachenzi')) # 打印name的值,并设置其的值为dachenzi
5、getrange 字符串的截取(类似字符串的切片)
r.getrange(name,start,end) # key 起始位置 结束位置 r.set('name','dachenzi') print(r.getrange('name',2,5)) # 则会打印 chen
6、setrange(name, offset, value) 字符串的分片替换
# r.setrange(name,offset,value) # key,偏移位置(起始位置), 要替换的字符串 #修改字符串内容,从指定字符串索引开始向后替换,如果新值太长时,则向后添加 r.set('name','dachenzi') r.setrange('name',5,'a') print(r.get('name')) # 打印dacheazi
7、strlen 统计字符串的字节长度
# r.strlen(name) r.set('name','dachenzi') print(r.strlen('name')) # 打印8 # 注意:一个汉字占用3个字节
8、incr/decr 自增/自减对应的值(整型)
# r.incr(name,amount) amount默认值为1 # 自增mount对应的值,当mount不存在时,则创建mount=amount,否则,则自增,amount为自增数(整数,也可以理解为步长) print(r.incr("mount",amount=2)) #输出:2 print(r.incr("mount")) #输出:3 print(r.incr("mount",amount=3)) #输出:6 print(r.incr("mount",amount=6)) #输出:12 print(r.get("mount")) #输出:12 # r.decr(name,amount) amount默认值为1 # 自减name对应的值,当name不存在时,则创建name=amount,否则,则自减,amount为自增数(整数)
9、append 在对应的key后面进行追加
# r.append(name,value) 在 name的对应的值后面追加value # name存在会追加,不存在会创建 r.set('name','daxin') r.append('name',' hello world') print(r.get('name)) # 打印: 'daxin hello world'
List
1、lpush(name,values) 向list中添加元素,FIFO模式(先进先出)
# 在name对应的list中添加元素,每个新的元素都添加到列表的最左边 r.lpush("daxin_list",2) r.lpush("daxin_list",3,4,5) print(r.lrange('daxin_list',0,-1)) 保存在列表中的顺序为5,4,3,2
2、rpush(name,values) 向list中添加元素,栈模式(先进后出)
# 在name对应的list中添加元素,每个新的元素都添加到列表的最右边 r.rpush("daxin_list2",2) r.rpush("daxin_list2",3,4,5) print(r.lrange('daxin_list2',0,-1)) # 2,3,4,5
3、lpushx(name,value) 在name对应的list中添加元素,只有name已经存在时,值添加到列表的最左边
4、rpushx(name,value) 在name对应的list中添加元素,只有name已经存在时,值添加到列表的最右边
5、llen(name) 获取name对应的list元素的个数
print(r.llen("daxin_list"))
6、linsert(name, where, refvalue, value)) 插入元素
# 在name对应的列表的某一个值前或后插入一个新值 r.linsert("daxin_list","BEFORE","2","SS")#在列表内找到第一个元素2,在它前面插入SS # 参数: # name: redis的name # where: BEFORE(前)或AFTER(后) # refvalue: 列表内的值 # value: 要插入的数据
7、lset(name, index, value) 对list中的某一个索引位置重新赋值
r.lset("daxin_list",0,"bbb")
8、lrem(name, value, count) 删除name对应的list中的指定值
r.lrem(name,value,count) # 参数: # name: redis的name # value: 要删除的值 # count > 0 : 从表头开始向表尾搜索,移除与 VALUE 相等的元素,数量为 COUNT 。 # count < 0 : 从表尾开始向表头搜索,移除与 VALUE 相等的元素,数量为 COUNT 的绝对值。 # count = 0 : 移除表中所有与 VALUE 相等的值。
9、lpop(name) 移除列表的左侧第一个元素,返回值则是第一个元素
print(r.lpop("daxin_list"))
10、lindex(name, index) 根据索引获取列表内元素
print(r.lindex("daxin_list",1))
11、lrange(name, start, end) 分片获取元素
print(r.lrange("daxin_list",0,-1)) # 0 表示 其实位置,-1表示末尾 # 所以 0,-1 就表示列表的所有
12、ltrim(name, start, end) 移除列表内没有在该索引之内的值
r.lrange('daxin_list') # 2,3,4,5 r.ltrim("daxin_list",0,2) # 会删除 5
13、rpoplpush(src, dst) 从src取出最右边的元素,同时将其添加至dst的最左边
r.lpush('dachenzi_list',1,2,3,4,5) r.lpush('dachenzi_list2',5,4,3,2,1) r.rpoplpush('dachenzi_list','dachenzi_list2') # dachenzi_list: 2,3,4,5 # dachenzi_list2: 1,1,2,3,4,5
14、brpoplpush(src, dst, timeout=0)
#同rpoplpush,多了个timeout, timeout:取数据的列表没元素后的阻塞时间,0为一直阻塞 r.brpoplpush("dachenzi_list","dachezi_list2",timeout=0)
15、blpop(keys, timeout)
#将多个列表排列,按照从左到右去移除各个列表内的元素 r.lpush("dachenzi_list",3,4,5) r.lpush("dachenzi_list2",3,4,5) while True: print(r.blpop(["dachenzi_list","dachenzi_list2"],timeout=0)) print(r.lrange("dachenzi_list",0,-1),r.lrange("dachenzi_list2",0,-1)) # 先挨个删除dachenzi_list,然后再挨个删除dachenzi_list2。 # r.blpop(keys,timout) # 参数: # keys: redis的name的集合 # timeout: 超时时间,获取完所有列表的元素之后,阻塞等待列表内有数据的时间(秒), 0 表示永远阻塞'''
16、brpop(keys, timeout) 同blpop,将多个列表排列,按照从右像左去移除各个列表内的元素
set之无序集合
Set集合就是不允许重复的列表,在redis中,集合分为无序和有序,set表示无序集合,sortes set表示有序集合
1、sadd(name,values) 给name对应的集合中添加元素
r.sadd('daxin_set1',1,2,3,4,5) r.sadd('daxin_set1',1,2,3,4,5,6,7) print(r.smembers('daxin_set1'))
2、smembers(name) 获取name对应的集合的所有成员
3、scard(name) 获取name对应的集合中的元素个数
r.sadd('daxin_set',1,2,3,4,5) r.sadd('daxin_set',1,2,3,4,5,6,7) print(r.scard('daxin_set')) # 打印7个
4、sdiff(keys, *args) 在第一个name对应的集合中且不在其他name对应的集合的元素集合(第一个set和其他set的差集)
r.sadd('daxin_set',1,2,3) r.sadd('daxin_set2',2) r.sadd('daxin_set3',3) print(r.sdiff('daxin_set','daxin_set2','daxin_set3')) # 打印1
5、sdiffstore(dest, keys, *args) 相当于把sdiff获取的值加入到dest对应的集合中
r.sadd('daxin_set',1,2,3) r.sadd('daxin_set2',2) r.sadd('daxin_set3',3) r.sdiffstore('daxin_set4','daxin_set','daxin_set2','daxin_set3') print(r.smembers('daxin_set4')) # 打印1
6、sinter(keys, *args) 获取同时存在指定集合中的元素
r.sadd('daxin_set',1,2,3) r.sadd('daxin_set2',2,1) r.sadd('daxin_set3',3,1) print(r.sinter('daxin_set','daxin_set2','daxin_set3')) # 打印1
7、sinterstore(dest, keys, *args) 获取多个name对应集合的并集,再讲其加入到dest对应的集合中
8、sismember(name, value) 检查value是否是name对应的集合内的元素
r.sadd('daxin_set','a','b','c') print(r.sismember('daxin_set','c')) # true print(r.sismember('daxin_set','d')) # false
9、smove(src, dst, value) 将某个元素从一个集合中移动到另外一个集合
r.sadd('daxin_set','a','b','c') r.sadd('daxin_set2',1,2) r.smove('daxin_set','daxin_set2','c') print(r.smembers('daxin_set2')) # 打印1,2,c
10、spop(name) 从集合的右侧移除一个元素,并将其返回
11、srandmember(name, numbers) 从name对应的集合中随机获取numbers个元素
r.sadd('daxin_set','a','b','c','d','e','f','g') print(r.srandmember('daxin_set',2)) # 随机取两个,每次都不同
12、srem(name, values) 删除name对应的集合中的某些值
r.sadd('daxin_set','a','b','c','d','e','f','g') print(r.srem('daxin_set','a','b','z')) # 返回实际删除的members个数,这里返回2 print(r.smembers('daxin_set'))
13、sunion(keys, *args) 获取多个name对应的集合的并集
r.sadd('daxin_set','a','b') r.sadd('daxin_set1','c','d') r.sadd('daxin_set2','e','f','g') print(r.sunion('daxin_set','daxin_set2','daxin_set1')) # 打印 {b'c', b'a', b'f', b'e', b'g', b'd', b'b'}
14、sunionstore(dest,keys, *args) 获取多个name对应的集合的并集,并将结果保存到dest对应的集合中
set之有序集合
在集合的基础上,为每元素排序,元素的排序需要根据另外一个值来进行比较,所以,对于有序集合,每一个元素有两个值,即:值和分数(可以理解为index,索引),分数专门用来做排序。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1、zadd(name, *args, **kwargs) 在name对应的有序集合中添加元素 # r.zadd(name,value,score...) r.zadd('daxin_set','name',1,'age',2,'job',3) print(r.zrange('daxin_set',0,-1)) # 打印 [b'name', b'age', b'job'] 2、zcard(name) 获取有序集合内元素的数量 3、zcount(name, min, max) 获取有序集合中分数在[min,max]之间的个数 r.zadd('daxin_set','name',1,'age',6,'job',3) print(r.zcount('daxin_set',1,2)) # 打印1 print(r.zcount('daxin_set',1,3)) # 打印2 4、zincrby(name, value, amount) 自增有序集合内value对应的分数 r.zadd('daxin_set','name',1,'age',6,'job',3) print(r.zrange('daxin_set',0,-1)) # 顺序是 [b'name', b'job', b'age'] r.zincrby('daxin_set','name',amount=7) # 改变了name的score,影响排序 print(r.zrange('daxin_set',0,-1)) # 顺序是 [b'job', b'age', b'name'] 5、zrange( name, start, end, desc=False, withscores=False, score_cast_func=float) 按照索引范围获取name对应的有序集合的元素 r.zrange("name",start,end,desc=False,withscores=True,score_cast_func=int) # 参数: # name redis的name # start 有序集合索引起始位置 # end 有序集合索引结束位置 # desc 排序规则,默认按照分数从小到大排序 # withscores 是否获取元素的分数,默认只获取元素的值 # score_cast_func 对分数进行数据转换的函数 r.zadd('daxin_set','name',1,'age',6,'job',3) print(r.zrange('daxin_set',0,1,withscores=True)) zrevrange(name, start, end, withscores=False, score_cast_func=float) #同zrange,集合是从大到小排序的 zrank(name, value)、zrevrank(name, value) #获取value值在name对应的有序集合中的排行位置(从0开始) print(r.zrank("zset_name", "a2")) print(r.zrevrank("zset_name", "a2"))#从大到小排序 zscore(name, value) #获取name对应有序集合中 value 对应的分数 print(r.zscore("zset_name","a1")) zrem(name, values) #删除name对应的有序集合中值是values的成员 r.zrem("zset_name","a1","a2") zremrangebyrank(name, min, max) #根据排行范围删除 zremrangebyscore(name, min, max) #根据分数范围删除 zinterstore(dest, keys, aggregate=None) 复制代码 复制代码 r.zadd("zset_name", "a1", 6, "a2", 2,"a3",5) r.zadd('zset_name1', a1=7,b1=10, b2=5) # 获取两个有序集合的交集并放入dest集合,如果遇到相同值不同分数,则按照aggregate进行操作 # aggregate的值为: SUM MIN MAX r.zinterstore("zset_name2",("zset_name1","zset_name"),aggregate="MAX") print(r.zscan("zset_name2")) 复制代码 复制代码 zunionstore(dest, keys, aggregate=None) #获取两个有序集合的并集并放入dest集合,其他同zinterstore,
其他常用操作
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
delete(*names) #根据name删除redis中的任意数据类型 exists(name) #检测redis的name是否存在 keys(pattern='*') #根据* ?等通配符匹配获取redis的name expire(name ,time) # 为某个name设置超时时间 rename(src, dst) # 重命名 move(name, db)) # 将redis的某个值移动到指定的db下 randomkey() #随机获取一个redis的name(不删除) type(name) # 获取name对应值的类型