这里的原子性跟mysql的原子性不一样。
redis事务的原子性是说的:一次事务提交的多个命令,要么都不执行(watch发现某个key的值变了则不开始执行),要么所有的命令都执行(一旦开始执行事务,事务中所有的命令都会执行,即使有命令报错了,后面的命令也会执行)
报错不回滚!
不回滚的原因:
● Redis 命令只会因为错误的语法而失败,失败的命令是由编程错误造成的。而这些错误应该在开发的过程中被发现,而不应该出现在生产环境中。
● 因为不需要对回滚进行支持,所以 Redis 的内部可以保持简单且快速。
只在特殊情况下有持久性。也就是做了持久化之后。且用AOF持久化,用always策略,保证每次操作都持久化。
1.pipeline是只有一次网络开销执行多个命令,而redis事务是N次网络开销执行N次命令。
2.pipeline不具备原子性,redis的事务具备原子性。
pipeline可能存在的场景是:
pipeline 中执行命令1 命令2 命令3 其他非pinpeline执行命令4 命令5
最后的结果可能是
命令1 命令4 命令2 命令5 命令3
redis用multi命令开启事务后,后面的命令都是放入队列中,遇到exec再真正的执行,放入队列中的命令不会立马返回结果,只是返回QUEUED表示成功放入命令。EXEC统一执行了之后统一返回每个命令的结果。
换句话说,如果我们想实现这个场景,用redis的事务就实现不了:
得到key=age1的数据,如果该数据存在且该数据为100,那么删掉该数据,否则不做操作。
因为在事务中get age1命令返回的时QUEUED,并不是返回的age1的值
而这个场景用redis lua脚本可以实现
用于标记事务的开始,其后执行的命令都将被存入命令队列,直到执行EXEC时这些命令才会被执行。或者遇到DISCARD命令
可以看到开启事务后,每次命令只是进入了该事务的命令队列,返回的是QUEUED,得执行了EXEC后才真的执行这些命令返回命令对应的执行结果。
执行在一个事务内命令队列中的所有命令,同时讲当前状态回复为正常状态,即是非事务状态。
如果在事务中执行了watch命令,那么只有当watch所监控的keys没有被修改的前提下,EXEC命令才能执行事务队列中所有的命令,否则EXEC讲放弃当前事务中的所有命令。
回滚事务队列中的所有命令,同时再将当前连接的事务状态恢复为正常状态,即是非事务状态。
如果WATCH命令被使用,该命令将UNWATCH所有的keys
可以看到并没有返回test_key_1的结果,也没有执行set test_key_2
WATCH 命令可以为 Redis 事务提供 check-and-set (CAS)行为。
在MULTI命令执行前,可以WATCH指定待监控的keys,然后在执行EXEC前,如果被监控的keys发生修改,那么整个事务都会被取消, EXEC 返回空多条批量回复(null multi-bulk reply)来表示事务已经失败。
WATCH 使得 EXEC 命令需要有条件地执行: 事务只能在所有被监视键都没有被修改的前提下执行, 如果这个前提不能满足的话,事务就不会被执行
取消当前事务中指定监控的keys,如果执行了EXEC或DISCARD命令,则无需再手工执行UNWATCH命令了。
1.在执行EXEC前,如果有很明显的错误,则不会开始执行事务
比如事务在执行 EXEC 之前,入队的命令可能会出错(比如:命令产生语法错误(参数数量错误,参数名错误,等等))
2.已经开始执行EXEC,发现有命令报错了(比如:事务中的命令可能处理了错误类型的键,比如将列表命令用在了字符串键上面)
这里可以看到虽然第二条命令报错了,但是第三条命令也执行,第一条命令也执行了没有回滚