事务提供了一种“将多个命令打包, 然后一次性、按顺序地执行”的机制, 并且事务在执行的期间不会主动中断 —— 服务器在执行完事务中的所有命令之后, 才会继续处理其他客户端的其他命令。
当你看到上面对事务的定义描述,难免会产生疑问,这个事务和管道有什么区别呢,看起来很像啊。
关于他们的区别,你可以重点掌握以下几点
客户端需要通过multi这个命令开启事务,服务端收到这个命令后,会对这个客户端的对象设置一个特殊的状态,进入这个状态后,客户端发送过来的后续命令不会立即执行,而是要等到客户端发送EXEC命令后,才会按照顺序执行已经缓存的所有命令。
有一点极容易搞错,千万不要以为你执行了multi命令后,其他客户端的命令就不会干扰和影响到你,redis的事务没有锁,它只是保证在收到exec命令,你之前发送的命令可以一次性执行完,仅是在这个过程中不会收到其他客户端命令的影响。在你发送exec命令之前,如果其他客户端的命令修改了某个key,而你在事务中也要操作这个key,那么它的命令执行在前,而你的命令执行在后,你的命令只有在服务端收到exec后才会真正被执行。
那么,怎么才能防止被别的客户端干扰呢,你可以使用watch
WATCH 命令用于在事务开始之前监视任意数量的键: 当调用 EXEC 命令执行事务时, 如果任意一个被监视的键已经被其他客户端修改了, 那么整个事务不再执行, 直接返回失败, 如果你担心某个key被别人修改,你就watch这个key
from redis.client import Redis
from redis.client import WatchError
r = Redis(host='127.0.0.1', port=6379, db=0, password='198671724zds')
with r.pipeline()as p:
try:
p.watch('coolpython')
value = int(p.get('coolpython'))
p.multi()
p.set('coolpython', value + 1)
p.execute()
except WatchError:
print('coolpython 被修改')
print(r.get('coolpython'))
watch要配合事务来使用,如果不开启事务,这个watch是起不到监控作用的,执行exec时,如果被watch的key被其他客户端修改了,事务执行失败,上面的代码应当加上try ... execpt 来捕捉watch抛出的异常
redis的事务,保证了一致性和隔离性,但不保证原子性和持久性。
事务的原子性要求一组操作,要么都成功,要么都不成功,而redis在执行事务时,如果某个命令执行失败了,它并不会尝试进行重试或者回滚,因而不能确保原子性。
事务的持久性要求对系统的影响是永久的,但redis是基于内存的,在不启动持久化功能时,必然无法满足持久性,而即使是在RDB和AOF模式下,也无法保证持久性,在RDB模式下,有可能在RDB文件更新之前redis挂掉了,AOF模式下,事务的命令执行后,虽然会将数据写入到AOF文件里,但这个过程是后台异步进行的,仍然有失败的可能。
QQ交流群: 211426309