Redis的五种数据类型
1.字符串
String类型既可以保存普通文字,也可以保存序列化的二进制数据,最大可以存储512M的数据
字符串指令:
(1)GETRANGE: 获得截取字符串内容
例: GETRANGE email 0 3 (0:起始位置、3:结束位置)
(2)STRLEN: 获得字符串长度
例: STRLEN email
(3)SETEX: 设置带有过期时间(秒)的KEY-VALUE
例: SETEX city 5 Beijing (5秒钟后就找不到city这条记录了)
(4)MSET: 设置多个KEY-VALUE
例: MSET username scott sex male
(5)MGET: 获得多个VALUE
例: MGET username sex
(6)APPEND: 用于在字符串结尾追加内容,返回key中字符串长度
例: APPEND temp 123
(7)INCR: 字符串自加1
例: INCER num
(8)INCRBY: 数字加上指定的整数值
例: INCRBY num 25
(9)INCRFLOAT: 数字加上指定的浮点数
例: INCRFLOAT num 3.5
(10)DECR: 数字自减1
例: DECR num
(11)DECRBY: 数字减去指定的整数值
例: DECRBY num 10
2.哈希
相当于在Redis的Value中,再定义了一个Key-Value的元素。
哈希指令:
(1)HSET: 设置哈希字段
例: HSET 8000 ename Tom
(2)HMSET: 设置哈希表多个字段
例: HMSET 8000 ename Tom job SALESMEN deptno 10
(3)HGET: 获得哈希表字段值
例: HGET 8000 ename
(4)HMGET: 获得多个哈希表字段值
例: HMGET 8000 ename job deptno
(5)HGETALL: 获得所有哈希表字段值
例: HGETALL 8000
(6)HKEYS: 获得所有哈希表字段(key)名
例: HKEYS 8000
(7)HLEN: 获得哈希表中的字段数量
例: HLEN 8000
(8)HEXISTS: 判断哈希表是否存在某个字段
例: HEXISTS 8000 job
(9)HVALS: 获得哈希表所有的value值
例: HVALS 8000
(10)HDEL: 删除哈希表的字段
例: HDEL 8000 job deptno
(11)HINCRBY: 让哈希表某个字段加上指定的整数值
例: HINCRBY 8000 deptno 10
(12)HINCRBYFLOAT: 让哈希表某个字段加上指定的浮点数
例: HINCRBY 8000 sal 35.5
3.列表
当我们需要向VALUE保存序列化的数据,可以用列表类型
列表指令:
(1)RPUSH: 向列表最右侧添加数据
例: RPUSH dname 技术部 后勤部
(2)LPUSH: 向列表最左侧添加数据
例: LPUSH dname 秘书部
(3)LSET: 修改列表元素(列表索引从0开始)
例: LSET dname 2 销售部 (2:被修改元素在列表中的索引)
(4)LRANGE: 输出列表中的元素
例: LRANGE dname 0 -1 (开始-结束的索引序号。-1代表全部的元素)
(5)LLEN: 获得列表长度
例: LLEN dname
(6)LINDEX: 获得列表某个元素
例: LINDEX dname 0 (索引序号)
(7)LINSERT: 在某个位置插入元素
例: LINSERT dname BEFORE 秘书处 董事会 (插入元素位于秘书处的前面)
(8)LPOP: 删除列表最左侧的元素
例: LPOP dname
(9)RPOP: 删除列表最右侧的元素
例: RPOP dname
(10)LREM: 删除列表某个元素
例: LREM employee 1 Jeff (列表中可以保存重复的元素。这个1表示删除一个“Jeff”)
4.集合
如果需要列表中的元素不可以重复,可以使用集合类型(集合中的元素是没有索引序号的,也不是按顺序存放的。)
(1)SADD: 向集合中添加元素
例: SADD empno 10001
(2)SMEMBERS: 获得集合中所有元素
例: SMEMBERS empno
(3)SCARD: 获得集合长度
例: SCARD empno
(4)SISMEMBER: 判断是否含有某个元素
例: SISMEMBER empno 10001
(5)SREM: 删除元素
例: SREM empno 10001 10002
(6)SPOP: 随机删除并返回集合的某个元素
例: SPOP empno
(2)SRANDMEMBER: 随机返回集合中n个元素
例: SRANDMEMBER empno 5 (随机返回5个元素)
5.有序集合
有序集合是带有排序功能的集合,Redis会按照元素分数值排序。若分数值相同,则按元素的哈希值排列。
(1)ZADD: 向有序集合中添加元素
例: ZADD keyword 0 “Jeff” 0 “Eason” 0 “Scott”
(2)ZINCRBY: 增加有序集合中元素的分数值n
例: ZINCRBY keyword 1 “Eason”
(3)ZREVRANGE: 返回有序集合中的元素,以分数值大小降序排列
例: ZREVRANGE keyword 0 -1 (从0开始,-1表示全部元素)
(4)ZCARD: 获得有序集合长度
例: ZCARD keyword
(5)ZCOUNT: 查询某个分数值区间内的元素数量
例: ZCOUNT keyword 5 10
(6)ZSCORE: 返回查询元素的分数值
例: ZSCORE keyword “Jeff”
(7)ZRANGE: 获得有序集合的内容(按分数值大小升序排列)
例: ZRANGE keyword 0 -1
(8)ZRANGEBYSCORE: 获得分数值区间内的集合内容(升序)
例: ZRANGEBYSCORE keyword 5 10 [获得分数值在5-10之间内的元素。若是: 5 (10 则代表不包括10。若是: 5 +inf 则代表大于等于5]
(9)ZREVRANGEBYSCORE: 获得分数值区间内的集合内容(降序)
例: ZREVRANGEBYSCORE keyword 10 5
(10)ZRANK: 获得元素的升序排名(从0开始)
例: ZRANK keyword “Jeff”
(11)ZREVRANK: 获得元素的降序排名(从0开始)
例: ZREVRANK keyword “Jeff”
(12)ZREM: 删除有序集合中的指定元素
例: ZREM keyword “Jeff” “Eason”
(13)ZREMRANGBYRANK: 删除排名区间内的元素
例: ZREMRANGBYRANK keyword 0 2
(14)ZREMRANGBYSCORE: 删除分数值区间内的元素
例: ZREMRANGBYRANK keyword -inf (5000 [ 删除分数值低于5000的元素(不包括5000) ]
Redis的Key命令
(1)DEL: 删除记录
例: DEL keyword
(2)EXISTS: 判断是否存在某个Key
例: EXISTS employee
(3)EXPIRE: 设置记录过期的时间
例: EXPIRE employee 5
(4)EXPIREAT: 设置记录的过期时间(UNIX时间戳)
例: EXPIREAT employee 1544803200 (距离1970年1月1日凌晨的时间。单位:秒)
(5)MOVE: 把记录迁移到其他逻辑库
例: MOVE keyword 1 (转移到1号逻辑库)
(6)RENAME: 修改Key名称
例: RENAME employee tmp
(7)PERSIST: 移除过期时间
例: PERSIST keyword
(8)TYPE: 判断value数据类型
例: TYPE keyword
Redis的事务
如何保持事务的一致性: 在开启事务前必须要用WATCH命令监视要操作的记录
如何开启事务: 利用MULTI命令。开启事务后所有的操作都不会立即执行,只有执行EXEC命令的时候才会批处理执行。
Redis与Python交互
创建连接:
import redis
r = redis.Redis(
host = “localhost”,
port = 6379,
password = “123456”,
db = 0
)
创建连接池: (从连接池中获取的连接,不必关闭。只需要删除引用[如 del r ],垃圾回收的时候,连接会被自动归还到连接池。)
import redis
r = redis.ConnectionPool(
host = “localhost”,
port = 6379,
password = “123456”,
db = 0,
max_connections = 20
)
redis-py中常用操作指令
例:
设置value:
con.set(“country”, “英国”)
取出value(需转码):
city = con.get(“city”).decode(“utf-8”)
删除value:
con.delete(“country”, “city”)
设置多个value:
con.mset({“country”: “德国”, “city”: “柏林”})
取出多个vaalue:
con.mget(“country”, “city”)
设置多个value进列表:
con.rpush(“dname”, “董事会”, “秘书处”, “财务部”, “技术部”)
删除列表最左端value:
con.lpop(“dname”)
获得全部列表value:
con.lrange(“dname”, 0, -1)
向集合中添加value:
con.sadd(“employee”, 8001, 8002, 8003)
删除集合中的value:
con.srem(“employee”, 8001)
获得集合中所有value:
con.smembers(“employee”)
向有序集合中添加多个元素:(注意语法,第二个参数必须是一个字典,且key在前,value在后)
con.zadd(“keyword”, {“马云”: 0, “张朝阳”: 0, “丁磊”: 0})
向有序集合中的key增加value的值:
con.zincrby(“keyword”, “10”, “马云”)
向哈希表中设置key-value:
con.hmset(“9527”, {“name”: “Scott”, “sex”: “male”, “age”: “35”})
向哈希表中增加key-value:
con.hset(“9527”, “city”, “NewYork”)
在哈希表中删除"age"这个key:
con.hdel(“9527”, “age”)
判断哈希表中"name"这个key是否存在:
con.hexists(“9527”, “name”)
获取哈希表中全部key-value并打印输出: (注意print函数中value的输出方式)
con.hgetall(“9527”)
for one in result:
print(one.decode(“utf-8”), result[one].decode(“utf-8”))
redis-py中的事务函数
redis-py模块中用pipline(管道)的方式向Redis服务器传递批处理命令和执行事务
例:
pipline = con.pipline()
pipline.watch(…)
pipline.multi()
pipline.execute()
pipline.reset()
实战一:线程池模拟用户抢购商品
import redis
from concurrent.futures import ThreadPoolExecutor
import random
# 创建redis连接池
pool = redis.ConnectionPool(
host="localhost",
port=6379,
password="123456",
db=0,
max_connections=20
)
# 模拟随机用户id
s = set()
while True:
if len(s) == 1000:
break
num = random.randint(10000, 100000)
s.add(num)
con = redis.Redis(
connection_pool=pool
)
try:
con.delete("kill_total", "kill_num", "kill_flag", "kill_user")
# 秒杀抢购总数
con.set("kill_total", 50)
# 抢购已卖出商品的数量
con.set("kill_num", 0)
# 秒杀抢购时间:10分钟.在此之前设置秒杀是否有效:flag=1。
con.set("kill_flag", 1)
con.expire("kill_flag", 600)
except Exception as e:
print(e)
finally:
del con
# 抢购
def buy():
connection = redis.Redis(
connection_pool=pool
)
pipeline = connection.pipeline()
try:
# 判断秒杀是否超时过期:
if connection.exists("kill_flag") == 1:
# 监视进程,防止超买超卖
pipeline.watch("kill_num", "kill_user")
# 总数和抢购数取出、转码
total = int(pipeline.get("kill_total").decode("utf-8"))
num = int(pipeline.get("kill_num").decode("utf-8"))
# 保证抢购数不超过总数
if num < total:
# 开启事务
pipeline.multi()
# 已抢购商品数量+1
pipeline.incr("kill_num")
# 从s列表中删除一个成功抢购的用户id,并返回
user_id = s.pop()
# 将抢购成功的用户id加入kill_user列表中
pipeline.rpush("kill_user", user_id)
# 提交事务
pipeline.execute()
except Exception as se:
print(se)
finally:
if "pipeline" in dir():
# 将事务还给连接池
pipeline.reset()
del connection
executor = ThreadPoolExecutor(200)
# 用进程池开启多线程:模拟1000个用户抢购商品
for i in range(0, 1000):
executor.submit(buy())
print("秒杀已经结束!")
实战二:模拟300名观众随机给大V投票并排名
import redis
import random
# 创建redis连接池
pool = redis.ConnectionPool(
host="localhost",
port=6379,
password="123456",
db=0,
max_connections=20
)
con = redis.Redis(
connection_pool=pool
)
try:
con.delete("ballot")
con.zadd("ballot", {"悔创阿里杰克马": 0, "被迫北漂撒贝宁": 0,
"不知妻美刘强东": 0, "一无所有王健林": 0,
"普通家庭马化腾": 0})
names = ["悔创阿里杰克马", "被迫北漂撒贝宁",
"不知妻美刘强东", "一无所有王健林",
"普通家庭马化腾"]
for i in range(0, 300):
num = random.randint(0, 4)
name = names[num]
con.zincrby("ballot", 1, name)
result = con.zrevrange("ballot", 0, -1, "WITHSCORES")
for one in result:
print(one[0].decode("utf-8"), int(one[1]))
except Exception as e:
print(e)
finally:
del con
实战三:解析本地数据并传入Redis缓存
import redis
# 创建redis连接池
pool = redis.ConnectionPool(
host="localhost",
port=6379,
password="123456",
db=0,
max_connections=20
)
con = redis.Redis(
connection_pool=pool
)
try:
file = open(file="grade.txt", mode="r", encoding="utf-8")
data = file.read().splitlines()
for one in data:
temp = one.split(",")
s_id = temp[0]
name = temp[1]
class_no = temp[2]
score_1 = int(temp[3])
score_2 = int(temp[4])
score_3 = int(temp[5])
if score_1 >= 85 and score_2 >= 85 and score_3 >= 85:
con.hmset(s_id, {"name": name, "class_no": class_no,
"score_1": score_1, "score_2": score_2,
"score_3": score_3})
print("执行成功!")
except Exception as e:
print(e)
finally:
if file in dir():
file.close()
del con
# grade.txt:
# 616,沈腾,2-1,96,89,75
# 617,欧阳攀,2-1,71,62,80
# 618,李雨,2-2,78,95,69
# 619,江北,2-2,96,88,89
# 620,苏意,2-3,98,99,100