Redis transaction
工作時有需要做一個
Set if key exists
發現 redis 只提供一個 SETNX,Set if key doesn’t exist
順便來研究一下 redis 的 transaction
MULTI
https://redis.io/topics/transactions
在 redis 裡面做 transaction 基本上就是使用 MULTI
MULTI
SET key0 value0
SET key1 value1
EXEC
Note: redis transaction 跟一般的 db transaction 有點不一樣,可以保證中間不被插入其他指令,照順序執行,但做到一半出錯不會 rollback,且甚至會繼續往下做
例如
SET a 1
SET b ssss
SET c 1
MULTI
INCR a
INCR b
INCR c
EXEC
1) (integer) 2
2) (error) ERR value is not an integer or out of range
3) (integer) 2
Redis 為何沒有 rollback:
https://redislabs.com/blog/you-dont-need-transaction-rollbacks-in-redis/
Redis persistency:
https://redis.io/topics/persistence?_ga=2.166846334.1799612137.1620217522-2107259978.1617716900
transaction 做到一半真的機器停住的話,可能真的只有一半指令進去,AOF的話就可以把多的那部分去掉,RDB的話應該是直接掉資料了(?
我們 Server 使用的是 https://github.com/go-redis/redis
裡面提供了 TxPipeline 就是接到 MULTI 上面
go-redis 提供的 Pipeline 沒有用 MULTI EXEC 包起來,中間有可能被切開,就是一次傳很多指令去 redis 減少 round trip 時間
使用方法也滿簡單的
|
|
不過還是沒辦法達到 set if key exists
如下面的範例,因為 exists 要等到 pipe.Exec() 之後才會有正確的值進去
|
|
估狗了一下發現只好用 WATCH 來 workaround
WATCH 可以監視一個 key
之後使用 MULTI EXEC 如果發現這個 key 被動過,就會 EXEC 失敗
WATCH key0
MULTI
SET xxx xxxxx
EXEC // 如果 key0 在 EXEC 之前被改過,就會失敗
所以要實現 set if key exists
就變成
// sudo code
WATCH key0
exists = EXISTS key0
if exists == True {
MULTI
SET xxx xxxxx
EXEC // 如果 key0 在 EXEC 之前被改過,就會失敗
}
但也不全然是只要存在就 set,因為當 key0 被改的時候也會不做
下面是 Go 裡面的做法
參考:https://www.tizi365.com/archives/309.html
|
|