redis事务的基本命令组合有:multi,exec,discard,watch;它们允许单步执行多个命令,并提供两个保证:
- 事务中的所有命令被放到缓存队列中顺序执行,操作具有隔离性
- 事务中的所有命令要么全部执行,要么都不执行,所以操作具有原子性,但是不保证每一个命令操作的正确性!
使用方法如:multi命令开启事务,exec命令执行所有的操作;multi和exec之间的操作命令会被缓存到一个队列中:
> MULTI
OK
> INCR foo
QUEUED
> INCR bar
QUEUED
> EXEC
1) (integer) 1
2) (integer) 1
上面是一个简单的事务操作,通过提示可以看出,redis是将命令都缓存到一个队列中进行执行的,但是命令执行正确与否确不保证,例如:
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr foo
QUEUED
127.0.0.1:6379> set bar xxx dd
QUEUED
127.0.0.1:6379> exec
1) (integer) 3
2) (error) ERR syntax error
可以看出上面的事务执行过程中,incr foo操作正常执行,set bar xxx dd命令执行失败,所以redis事务没有回滚操作!为什么redis不支持事务呢?它有自己的解释:
- redis命令在语法错误的情况下会执行失败,这时候事务就会执行失败,这种错误在开发过程中也很容易被发现
- redis因为不支持回滚,所以内部事务的执行被简化了,因而执行速度也更快
总之,在可确定命令不出错的情况下,redis事务的执行效率是很高的
discard用于终止事务的执行:
> SET foo 1
OK
> MULTI
OK
> INCR foo
QUEUED
> DISCARD
OK
> GET foo
"1"
watch用于在事务中提供一个check-and-set(CAS)的作用,用于监控key值是否改变,watch可以监控多个key值,如果被监控的key值改变了或者被删除了,则事务执行失败:
127.0.0.1:6379> set key 1
OK
127.0.0.1:6379> watch key ### 监控key值
OK
127.0.0.1:6379> set key 2 ### 修改key值
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set key 3 ### key的监控值被修改了
QUEUED
127.0.0.1:6379> exec ### 执行失败
(nil)
127.0.0.1:6379> get key ###得到是2
"2"
上面是修改被监控的对象key的值后再执行事务
127.0.0.1:6379> set key 1
OK
127.0.0.1:6379> watch key
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set key 2
QUEUED
127.0.0.1:6379> exec
1) OK
127.0.0.1:6379> get key
"2"
上面是监控的值并没有改变,而是在事务中执行对该key赋值的操作,可见事务执行成功
同样,如果在事务执行之前,如果key值被删除了,事务执行也会失败。