1. MULTI标记事务开始,事务块内的多条命令会按照先后顺序被放进一个队列当中。而EXEC则用于执行事务块内所有的命令。
Command
$ redis-cli.exe -h 127.0.0.1 -p 6379
127.0.0.1:6379> set dog 1
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> INCR dog
QUEUED
127.0.0.1:6379> INCR dog
QUEUED
127.0.0.1:6379> EXEC
1) (integer) 2
2) (integer) 3
Code
pool.FactoryPool()
是自己的连接池工厂函数,此处不特别记录。
func MultiAndExec() {
c := pool.FactoryPool()
defer c.Close()
defer c.Do("DEL", "dog")
c.Do("SET", "dog", 1)
res, _ := c.Do("MULTI")
fmt.Println("Result of MULTI:", res)
// Add commands into queue.
res, _ = c.Do("INCR", "dog")
fmt.Println("Result of adding command:", res)
res, _ = c.Do("INCR", "dog")
fmt.Println("Result of adding command:", res)
// Execute all the commands in transaction.
results, _ := redis.Ints(c.Do("EXEC"))
for _, v := range results {
fmt.Println(v)
}
}
Output
$ go run main.go
Result of MULTI: OK
Result of adding command: QUEUED
Result of adding command: QUEUED
2
3
2. DISCARD用于取消事务,即放弃执行事务内的所有命令。
可以看到,当使用DISCARD取消事务后,EXEC返回错误。
Command
$ redis-cli -h 127.0.0.1 -p 6379
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> incr dog
QUEUED
127.0.0.1:6379> DISCARD
OK
127.0.0.1:6379> EXEC
(error) ERR EXEC without MULTI
Code
func Discard() {
c := pool.FactoryPool()
defer c.Close()
defer c.Do("DEL", "dog")
c.Do("SET", "dog", 1)
res, _ := c.Do("MULTI")
fmt.Println("Result of MULTI:", res)
// Add commands into queue.
res, _ = c.Do("INCR", "dog")
fmt.Println("Result of adding command:", res)
// Cancel the transaction.
res, _ = c.Do("DISCARD")
fmt.Println("Result of DISCARD:", res)
// Execute all the commands in transaction, will return nil.
resAfterDis, err := c.Do("EXEC")
if err != nil {
colorlog.Error(err.Error())
}
fmt.Println(resAfterDis)
}
Output
$ go run main.go
Result of MULTI: OK
Result of adding command: QUEUED
Result of DISCARD: OK
[ERR]2020/04/21 22:45:40 ERR EXEC without MULTI
ERR EXEC without MULTI
3. WATCH用于监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断
Command
- 在第一个终端监视"dog",并标记事务开始,添加命令到队列
$ redis-cli.exe -h 127.0.0.1 -p 6379
127.0.0.1:6379> WATCH dog
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> incr dog
QUEUED
127.0.0.1:6379> incr dog
QUEUED
- 在第二个终端改变"dog"的值,用于打断事务
$ redis-cli -h 127.0.0.1 -p 6379
127.0.0.1:6379> set dog 10
OK
- 再在第一个终端执行EXEC。事务已被打断,EXEC返回nil
127.0.0.1:6379> EXEC
(nil)
Code
func Watch() {
c1 := pool.FactoryPool()
c2 := pool.FactoryPool()
defer c1.Close()
defer c2.Close()
defer c1.Do("DEL", "dog")
c1.Do("SET", "dog", 1)
watchRes, _ := c1.Do("WATCH", "dog")
fmt.Println("Result of watch is:", watchRes)
res, _ := c1.Do("MULTI")
fmt.Println("Result of MULTI:", res)
// Add commands into queue.
res, _ = c1.Do("INCR", "dog")
fmt.Println("Result of adding command:", res)
res, _ = c1.Do("INCR", "dog")
fmt.Println("Result of adding command:", res)
// Set dog's value in second connection.
c2.Do("SET", "dog", 10)
// Execute all the commands in transaction in first connection.
resAfterWatchAndSet, _ := c1.Do("EXEC")
fmt.Println("After WATCH and SET, result of EXEC is:", resAfterWatchAndSet)
}
4. UNWATCH用于取消WATCH命令对所有key的监视。但是据观察,貌似必须跟WATCH命令在同一个连接里,才能起到效果?
Command
- 在第一个终端里开始WATCH
$ redis-cli.exe -h 127.0.0.1 -p 6379
127.0.0.1:6379> watch dog
OK
- 在第二个终端里标记事务但不执行
$ redis-cli -h 127.0.0.1 -p 6379
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr dog
QUEUED
127.0.0.1:6379> incr dog
QUEUED
- 在第一个终端里取消监视,并改变"dog"的值
127.0.0.1:6379> unwatch
OK
127.0.0.1:6379> set dog 33
OK
- 在第二个终端里执行事务。可以看到事务正常执行,因为修改"dog"的值之前,已经取消监视
127.0.0.1:6379> exec
1) (integer) 34
2) (integer) 35
Code
func Unwatch() {
c1 := pool.FactoryPool()
c2 := pool.FactoryPool()
defer c1.Close()
defer c2.Close()
defer c1.Do("DEL", "dog")
c1.Do("SET", "dog", 1)
watchRes, _ := c1.Do("WATCH", "dog")
fmt.Println("Result of watch is:", watchRes)
res, _ := c2.Do("MULTI")
fmt.Println("Result of MULTI:", res)
// Add commands into queue.
res, _ = c2.Do("INCR", "dog")
fmt.Println("Result of adding command:", res)
res, _ = c2.Do("INCR", "dog")
fmt.Println("Result of adding command:", res)
// Unwatch, and then set dog's value.
unwatchRes, _ := c1.Do("UNWATCH")
fmt.Println("Result of unwatch is:", unwatchRes)
c1.Do("SET", "dog", 33)
// Execute all the commands in transaction in first connection.
resAfterUnwatchAndSet, _ := redis.Ints(c2.Do("EXEC"))
for _, v := range resAfterUnwatchAndSet {
fmt.Println(v)
}
}
Output
$ go run main.go
Result of watch is: OK
Result of MULTI: OK
Result of adding command: QUEUED
Result of adding command: QUEUED
Result of unwatch is: OK
34
35