Closed jiangyoucai closed 7 years ago
So you're pretty close. I really recommend checking for errors at every step, even though it's a bit of a pain. Also you need to make sure you call PipeResp
for every time that you've called PipeAppend
, or use PipeClear
if you know you don't care about the responses (but in this case you probably want to know if your transaction succeeded, so you do want the responses). So something like this:
if err := cache.Conn.Cmd("WATCH", "5").Err; err != nil {
// handle error
}
d, err := cache.Conn.Cmd("GET", "5").Str()
if err != nil {
// handle error
}
if d != "5" {
if err := cache.Conn.Cmd("UNWATCH"); err != nil {
// handle error
}
// handle d not being "5"
return
}
cache.Conn.PipeAppend("MULTI")
cache.Conn.PipeAppend("SET", "key1", "1")
cache.Conn.PipeAppend("SET", "key2", "2")
cache.Conn.PipeAppend("SET", "key3", "3")
cache.Conn.PipeAppend("SET", "key4", "4")
cache.Conn.PipeAppend("SET", "key5", "5")
cache.Conn.PipeAppend("EXEC")
for i := 6; i >= 0; i-- {
r := cache.Conn.PipeResp()
if r.Err != nil {
// handle error
} else if i == 0 {
// This will be the actual response to EXEC. This is where you'll
// find out if your transaction actually succeeded, if the reply is
// nil it means it failed because "5" was changed
if r.IsType(redis.Nil) {
// transaction failed
}
}
}
An alternative I'd really recommend is looking into the lua EVAL stuff. antirez has basically stated that lua is the way forward for people doing transactional stuff, the WATCH/MULTI/EXEC stuff is only left for backwards compatibility. It's still a bit of a pain because you have to learn lua, but you end up with much cleaner and simpler code. Lua eval is also faster in cases where you'd otherwise have to use WATCH, because you don't have to retry your transactions, they're always atomic. For your case you'd end up with something like this:
script := `
if redis.call("GET", "5") ~= "5" then
return nil
end
for i = 1, #KEYS do
redis.call("SET", KEYS[i], ARGV[i])
end
return "OK"
`
r := util.LuaEval(cache.Conn, script, 5,
"key1", "key2", "key3", "key4", "key5",
"1", "2", "3", "4", "5",
)
log.Print(r)
Note I hardcoded the check on "5"
, but you could make that part of the arguments to your script as well if that's something which changes. LuaEval
is also nice because it'll work with a Pool or Cluster automatically.
Hope this helps, lemme know if you have any more questions :)
Usually, I use lua as a server deployment script and openresty widget I will try it with redis. thank you very much.
No problem! If you're used to openresty then you should have no problem here, redis' lua support is way simpler. I'll go ahead and close this now, but feel free to open it back up if you've got any other questions.
I am building a web store I use locks and transactions to ensure proper inventory But how do I use the transaction? I wrote the following code But I'm not sure this is right
Can you give me some suggestions ?