redis學習(九) redis事務和redis指令碼的比較
如果想要實現一組命令原子性的執行,一種方法是使用事務,一種方法使用redis指令碼,可以對比下兩種方式的區別
Redis事務回顧
事務命令:MULTI, EXEC, DIDCARD ,WATCH ,UNWATCH
使用: MULTI : 開啟一個事務,並會生成一個任務佇列,客戶端傳送的指令都會放在任務佇列中,總是返回OK
EXEC: 執行任務佇列中的命令,成功返回OK,失敗返回nil
DIDCARD: 清空任務佇列中的所有命令,並取消事務的執行
WATCH:監控一個或者多個鍵,如果鍵被修改了, 就會阻止後面一個事務的執行,但是不會阻止其他客戶端對鍵的修改(不通過事務),所有的鍵的監控的取消在exec命令執行後,也可以通過執行UNWATCH命令取消對鍵的監控,客戶端斷開連線也會,取消監控
127.0.0.1:6379> get zhouy
"2222222222"
127.0.0.1:6379> get zhouy
"2222222222"
127.0.0.1:6379> watch zhouy
OK
127.0.0.1:6379> set zhouy 1993
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set zhouy 1990
QUEUED
127.0.0.1:6379> exec
(nil)
127.0.0.1:6379> get zhouy
"1993"
127.0.0.1:6379>
事務沒有執行成功,key的值還是1993,而且watch一個鍵後,對這個鍵修改,如果另一個客戶端不通過事務修改這個鍵,也是能夠執行成功的,這點需要注意
127.0.0.1:6379> watch zhouy
OK
127.0.0.1:6379> set zhouy 11111
OK
127.0.0.1:6379> get zhouy
"9999"
事務的特性: 一致性,原子性(事務中的一組命令,要麼全部成功,要麼全部失敗),永續性,隔離性(多個事務提交不會相互影響,由於redis是單執行緒的,提交的事務按順序執行)
使用watch的場景: 一般在多執行緒環境下,對一個鍵的更改產生了競態錯誤
$value = get key
$value = $value+1;
set key $value
此時,可以使用watch命令,實現cas的機制。
watch key
$value = get key
$value = $value +1
multi
set key $value
exec
這樣,每個連線執行exec命令前,如果key被其他客戶端修改了,當前連線執行exec就會失敗,可以根據返回值判斷是否設定成功,沒有成功,再次執行。
事務執行錯誤的場景
事務中的錯誤:
1、錯誤發生在呼叫CALL之前,例如語法錯誤(引數數量錯誤,命令拼寫錯誤....)。
2、錯誤發生在呼叫CALL之後,引數型別錯誤,例如對一個string型別的key使用list操作。
對於第一個錯誤,客戶端可以很容易的避免:向佇列中每新增一個命令都會返回“QUEUE”字串,表示新增成功,否則返回一個錯誤;客戶端可以取消事務的執行。
從版本2.6.5開始,服務端會記錄這種錯誤,在呼叫EXEC命令時,會拒絕這次事務的執行,並且自動取消事務。
對於第二類錯誤,即使發生了錯誤,Redis不會取消事務的執行。執行結果以會返回給客戶端,由客戶端決定。
Redis不支援事務回滾,執行後產生的影響需要程式設計師,自己去維護
Redis取消事務 DIDCARD命令終止事務
Redis Lua指令碼的特性
和redis事務類似,Lua指令碼的功能是將redis命令打包為一個Lua指令碼,在伺服器端原子執行。和redis的事務特性相比,減少了網路開銷,一次提交打包的命令;原子性執行避免出現watch的競態條件;同時可以被複用,儲存之後繼續使用
在指令碼中呼叫redis命令
call 和 pcall -- redis.call ('get',key) ,自動將Redis的資料型別轉為lua資料型別
兩者的區別在於:call如果執行失敗,停止執行,並且返回一個指令碼錯誤,pcall如果執行錯誤,會記錄錯誤,並繼續執行。
從指令碼中返回值
在指令碼中使用return將指令碼的執行結果返回給客戶端,如果沒有執行return語句預設返回nil,在此過程中也會自動將lua型別轉為redis資料型別
EVAL命令執行指令碼
執行格式: EVAL 指令碼內容 key引數的數量 [key...] [arg...]
127.0.0.1:6379> eval "return redis.call('set',KEYS[1],argv[1]) " 1 testkey helllo
(error) ERR Error running script (call to f_187b569d90860e5f8c7eda2a3b9139e91f659414): @enable_strict_lua:15: user_script:1: Script attempted to access nonexistent global variable 'argv'
127.0.0.1:6379> eval "return redis.call('set',KEYS[1],ARGV[1]) " 1 testkey helllo
OK
注意到,KEYS ,ARGV這兩個全域性變數是需要大寫的,(Lua語言是區別大小寫的),寫Lua指令碼的時候需要注意
當指令碼不需要任何引數的時候,不能省略這個引數(keynumber需要設定為0)
jedis中如何呼叫
tring script ="local result={} " +
" for i,v in ipairs(KEYS) do " +
" result[i] = redis.call('get',v) " +
" end " +
" return result ";
Jedis jedis = new Jedis(ip,port);
jedis.eval(script,keyCount,String … params);
注意的是,Lua指令碼中不能出現耗時比較長的操作,不能出現死迴圈,否則redis將不接受其他命令,執行去停止指令碼執行了
,redis提供了lua-time-limit引數現在指令碼最長執行時間,預設是5秒
其他命令:
1. 將指令碼加入快取 SCRIPT LOAD
每次執行eval命令時,redis會將指令碼的sha1摘要加入到指令碼快取中,以便下次客戶端可以使用evalsha命令呼叫指令碼,如果只是加入快取,使用SCRIPT LOAD
2. 是否快取指令碼 SCRIPT EXISTS +指令碼摘要 1:是 0:否
3. SCRIPT FLUSH 清空指令碼快取
4. SCRIPT KILL 終止正在執行的指令碼 ,如果當前執行的指令碼,修改了redis的資料(修改,刪除,更新key),這個命令就不會停止指令碼執行,防止指令碼只執行了一部分,此時只能使用 SHUTDOWN NOSAVE強制停止.
相關文章
- 【Redis 系列】redis 學習六,redis 事務處理和監控事務Redis
- Redis系列(九):Redis的事務機制Redis
- Redis篇:事務和lua指令碼的使用Redis指令碼
- Redis 和 Memcached 比較Redis
- MongoDB和Redis比較。MongoDBRedis
- etcd和redis比較Redis
- 詳解事務模式和Lua指令碼,帶你吃透Redis 事務模式指令碼Redis
- redis命令之-script指令碼學習Redis指令碼
- Redis的事務Redis
- Redis 事務Redis
- redis事務Redis
- 【Redis】Redis 學習Redis
- Redis系列12:Redis 的事務機制Redis
- 【Redis與Memcached比較】Redis
- redis學習——基礎指令Redis
- Redis的指令碼Redis指令碼
- 【Redis 系列】redis 學習八,redis 持久化 RDB 和 AOFRedis持久化
- Redis 中的事務Redis
- 一文講透 Redis 事務 (事務模式 VS Lua 指令碼)Redis模式指令碼
- Redis事務操作Redis
- redis-事務Redis
- Lua 指令碼在 Redis 事務中的應用實踐指令碼Redis
- Lua指令碼在Redis事務中的應用實踐指令碼Redis
- 為什麼在 Redis 實現 Lua 指令碼事務?Redis指令碼
- 【Redis 系列】redis 學習十一,redis 的哨兵模式詳解和實戰Redis模式
- Redis vs. MongoDB比較RedisMongoDB
- redis原始碼學習Redis原始碼
- [Redis 系列]redis 學習二Redis
- 【Redis 系列】redis 學習二Redis
- 十、Redis事務、事務鎖Redis
- Memcached 及 Redis 架構分析和比較Redis架構
- redis原始碼分析(六)、redis命令學習總結—Redis 集合(Set)Redis原始碼
- 雞肋的Redis事務Redis
- redis的事務處理Redis
- Redis - Lua 指令碼Redis指令碼
- Redis--事務理解Redis
- NoSql-Redis事務SQLRedis
- 【Redis學習筆記】2018-07-11 Redis指令學習5Redis筆記