事務(wù)
-
操作
# ex,過期時(shí)間(秒) # px,過期時(shí)間(毫秒) # nx,如果設(shè)置為True,則只有name不存在時(shí),當(dāng)前set操作才執(zhí)行 # xx,如果設(shè)置為True,則只有name存在時(shí),當(dāng)前set操作才執(zhí)行 redis_client.set('name', 'zs', ex=10)
-
事務(wù):
-
語法:
MULTI (multi):開啟事務(wù),后續(xù)的命令會(huì)被加入同一個(gè)事務(wù)中。 事務(wù)中的操作會(huì)發(fā)送給服務(wù)端,但是不會(huì)立即執(zhí)行, 而是放到了該事務(wù)的對(duì)應(yīng)的一個(gè)隊(duì)列中,服務(wù)端返回QUEUED
EXEC (exec):python文件引用中是execute,執(zhí)行EXEC后,事務(wù)中的命令才會(huì)被執(zhí)行,事務(wù)中的命令出現(xiàn)錯(cuò)誤時(shí),不會(huì)回滾也不會(huì)停止事務(wù), 而是繼續(xù)執(zhí)行。
DISCARD(discard):取消事務(wù),事務(wù)隊(duì)列會(huì)清空,客戶端退出事務(wù)狀態(tài)
-
ACID:
原子性:不支持。不會(huì)回滾并且繼續(xù)執(zhí)行
隔離性:支持。事務(wù)中命令順序執(zhí)行,并且不會(huì)被其他客戶端打斷(先EXEC的先執(zhí)行)。單機(jī)redis讀寫操作使用 單進(jìn)程單線程
持久性:不支持,因?yàn)閞edis數(shù)據(jù)容易丟失
一致性:不支持。 強(qiáng)一致性要求,可以通過樂觀鎖(watch)來實(shí)現(xiàn)
-
WATCH:
- redis機(jī)制的樂觀鎖
- 機(jī)制:事務(wù)開啟前,設(shè)置對(duì)數(shù)的監(jiān)聽,EXEC時(shí),如果發(fā)現(xiàn)數(shù)據(jù)發(fā)生過修改,事務(wù)會(huì)自動(dòng)取消(DISCARD)。事務(wù)EXEC后,無論成敗,監(jiān)聽會(huì)被移除。
-
setnx和悲觀鎖
- setnx鍵不存在,才會(huì)設(shè)置成功
-
非事務(wù)性管道
- redis實(shí)現(xiàn)了管道機(jī)制,可以將多個(gè)操作打包發(fā)給redis服務(wù)器
- 可以單獨(dú)使用管道,不需要開啟事務(wù) 對(duì)于沒有事務(wù)要求的多個(gè)操作,可以直接使用非事務(wù)性管道進(jìn)行處理,減少事務(wù)產(chǎn)生的性能消耗。
- 創(chuàng)建非事務(wù)性管道,通過transaction=False參數(shù)設(shè)置
-
redis樂觀鎖實(shí)現(xiàn)秒殺超賣需求
from redis import StrictRedis, WatchError
# 創(chuàng)建redis連接
# decode_responses = True 是指定數(shù)據(jù)是字符串的格式,host是連接地址,port是連接端口,db是連接的數(shù)據(jù)庫。
redis_client = StrictRedis(host='127.0.0.1', port=6379, db=0, decode_responses=True)
# 1. 創(chuàng)建管道 默認(rèn)會(huì)開啟事務(wù)
pipeline = redis_client.pipeline()
while True:
try:
# 2. 設(shè)置數(shù)據(jù)的監(jiān)聽 一旦設(shè)置了監(jiān)聽 就不會(huì)自動(dòng)開啟事務(wù) 后續(xù)操作都會(huì)變成立即執(zhí)行
pipeline.watch('count')
# 3. 獲取數(shù)據(jù) 可以立即得到結(jié)果
count = pipeline.get('count')
# 判斷庫存滿足,滿足減少庫存并生成訂單
if int(count) > 0:
# 4. 手動(dòng)開啟事務(wù) 開啟后 后續(xù)的操作會(huì)加入到事務(wù)中
pipeline.multi()
# 減少庫存
pipeline.decr('count')
# 提交事務(wù) 如果監(jiān)聽的數(shù)據(jù)中途被修改,會(huì)拋出WatchErrou錯(cuò)誤,可以捕獲異常,
pipeline.execute() # 無論成功失敗, 監(jiān)聽都會(huì)移除
print('生成訂單')
else:
# 沒有庫存,手動(dòng)移除監(jiān)聽
pipeline.reset()
print("已售罄")
break
except WatchError as e:
# 監(jiān)聽的數(shù)據(jù)被修改,重試。
print("重試")
continue
# 在redis 終端設(shè)計(jì)一個(gè)庫存數(shù)據(jù)
在redis 終端設(shè)計(jì)一個(gè)庫存數(shù)據(jù)

1562764435772.png
redis悲觀鎖實(shí)現(xiàn)秒殺超賣需求
from redis import StrictRedis
# 創(chuàng)建redis連接
# decode_responses = True 是指定數(shù)據(jù)是字符串的格式,host是連接地址,port是連接端口,db是連接的數(shù)據(jù)庫。
redis_client = StrictRedis(decode_responses=True)
while True:
# 設(shè)置個(gè)字段 a 并且等于1 setnx 鍵不存在,才會(huì)設(shè)置成功
order_lock = redis_client.setnx('a', 1)
if order_lock:
reserver_count = redis_client.get('count')
if int(reserver_count) > 0:
redis_client.decr('count')
print('生成訂單')
else:
print('已售罄')
# 完成處理,移除鎖
redis_client.delete('a')
break
非事務(wù)管道
from redis import StrictRedis
redis_client = StrictRedis(decode_responses=True)
# 創(chuàng)建非事務(wù)型管道 通過teansaction = False 設(shè)置
pipeline = redis_client.pipeline(transaction = False)
# 這些操作不會(huì)添加到事務(wù)中
a = pipeline.set('name','zs')
# 只是將管道中的操作一起發(fā)送給redis服務(wù)器, 不會(huì)進(jìn)行watch遍歷和檢查
c = pip.execute()
print(a)
print(c)