redis事務提供了一種將多個命令請求打包,然後一次性、按照順序地執行多個命令的機制,並且在事務執行的期間,伺服器不會中斷事務而去執行其他不在事務中的命令請求,它會把事務中所有的命令都執行完畢才會去執行其他的命令。
howredis中提供了multi、discard、exec、watch、unwatch這幾個命令來實現事務的功能。
redis的事務始於multi命令,之後跟著要在事務中執行的命令,終於exec命令或者discard命令。加入事務中的所有命令會原子的執行,中間不會穿插執行其他沒有加入事務的命令。
multi、exec和discard
multi命令告訴redis客戶端要開始乙個事物,然後redis會返回乙個ok,接下來所有的命令redis都不會立即執行,只會返回queued結果,直到遇到了exec命令才會去執行之前的所有的命令,或者遇到了discard命令,會拋棄執行之前加入事務的命令。
127.0.0.1:6379> get name
(nil)
127.0.0.1:6379> get gender
(nil)
127.0.0.1:6379> multi
ok127.0.0.1:6379> set name slogen
queued
127.0.0.1:6379> set gender male
queued
127.0.0.1:6379> exec
1) ok
2) ok
127.0.0.1:6379> mget name gender
1) "slogen"
2) "male"
watch
watch命令是redis提供的乙個樂觀鎖,可以在exec執行之前,監視任意數量的資料庫key,並在exec命令執行的時候,檢測被監視的key是否至少有乙個已經被修改,如果是的話,伺服器將拒絕執行事務,並向客戶端返回代表事務執行失敗的空回覆。
首先在client1執行下列命令:
127.0.0.1:6379> get name
(nil)
127.0.0.1:6379> watch name
ok127.0.0.1:6379> multi
ok127.0.0.1:6379> set name slogen
queued
127.0.0.1:6379> set gender male
queued
127.0.0.1:6379> get name
queued
這個時候client還沒有執行exec命令,接下來在client2下執行下面命令修改name:
127.0.0.1:6379> set name rio
ok127.0.0.1:6379> get name
"rio"
接下來在client1下執行exec命令:
127.0.0.1:6379> exec
(nil)
127.0.0.1:6379> get name
"rio"
從執行結果可以看到,在client1中執行exec命令的時候,redis會檢測到name欄位已經被其他客戶端修改了,所以拒絕執行事務中所有的命令,直接返回nil表示執行失敗。這個時候獲取到的name的值還是在client2中設定的rio。
whymulti
redis的事務始於multi命令,那麼就從multi命令的源**開始分析。
當redis接收到客戶端傳送過來的命令之後會執行multicommand()這個方法,這個方法在multi.c檔案中。
void multicommand(client *c) {
// 1. 如果檢測到flags裡面已經包含了client_multi
// 表示對應client已經處於事務的上下文中,返回錯誤
if (c->flags & client_multi) {
addreplyerror(c,"multi calls can not be nested");
return;
// 2. 開啟flags的client_multi標識
c->flags |= client_multi;
// 3. 返回ok,告訴客戶端已經成功開啟事務
addreply(c,shared.ok);
從源**中可以看到,multicommand()主要完成下面三件事:
檢測傳送multi命令的client是否已經處於事務中,如果是則直接返回錯誤。從這裡可以看到,redis不支援事務巢狀執行。
給對應client的flags標誌位中增加multi_client標誌,表示已經進入事務中。
返回ok告訴客戶端已經成功開啟事務。
Redis原始碼學習之 Tcp Socket封裝
anet.h anet.c 主要包含以下幾個封裝函式 這裡僅介紹關於tcp socket的封裝函式 anettcpconnect 建立socket並呼叫底層的connect進行連線。anettcpnonblockconnect 和anettcpconnect功能類似,但是設定連線的socket為非阻...
redis原始碼學習之跳躍表
跳躍表對於我來說是乙個比較陌生的資料結構,因此花了一上午的時間先看了一蛤mit的公開課。網易雲課堂 mit跳躍表 什麼是跳躍表,有乙個很簡單的例子,有些地方的火車站跟高鐵站是同乙個站,有的地方只有火車站 假設現在的線路是a b c d e。其中a和c剛剛說的高鐵和火車站在一塊,其他的只有火車站,考慮...
redis原始碼學習之整數集合
intset的底層實現比較簡單,因為它所有的key都是整型,只是整型分為16bits 32bits和64bits這三種型別,當新插入的元素比當前集合中所有數還要長時,就要進行公升級了,這部分原始碼很簡單,主要就是公升級部分。intset 的編碼方式 define intset enc int16 s...