Redis 原始碼學習之 Redis 事務Nosql

2022-06-11 12:06:09 字數 2291 閱讀 1917

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...