redis点滴 事务(二)

    xiaoxiao2021-12-14  22

    redis事务 

    multi exec discard 和watch 是redis事务的基础

    事务可以一次执行多个命令,并且带有以下两个重要的保证:

     1 事务是一个单独的隔离操作:事务中所有的命令都会序列化,按顺序地执行。事务在执行的过程中,不会被其它来的命令请求打断

     2.事务是一个原子操作:事务中的命令要么全部地执行,要么全部都不执行

     EXEC 命令负责触发并执行事务中所有命令:

      1.如果客户端在使用multi 开启一个事务之后,却因为断线而没有成功执行EXEC,那么事务中所有命令都不会执行

      2.另一方面,如果客户端成功在开启事务之后执行EXEC,那么事务中所有命令都会执行

      例如 购票过程,

      ticket-1 ,mobey-100

     而票只有一张,如果在multi之后,跟EXEC之前,被别人买了,所以ticket为0

      那我该如何监视这种情景,并不提交

      悲观的想法:觉得所有的人都在跟我抢这个ticket,此时给ticket上锁,只有我能操作【悲观锁】

      乐观的想法:我只需要注意这个ticket的值就可以了【乐观锁】

     redis的事务中就是开启了乐观锁,只负责监听ticket有没有被改动

     用法

    multi 命令用户开启一个事务,它总是返回ok

    multi 执行之后,客户端可以继续向服务端发送任意多条命令,这些命令不会立即执行,而是被放到一个队列中,当需要调用时,所有队列中的命令才会被执行

    另一方面,通过调用discard,客户端会清除事务队列,并放弃执行事务

    以下是一个事务例子, 它原子地增加了 foo 和 bar 两个键的值:

    > MULTI OK > INCR foo QUEUED > INCR bar QUEUED > EXEC 1) (integer) 1 2) (integer) 1

    EXEC 命令的回复是一个数组, 数组中的每个元素都是执行事务中的命令所产生的回复。 其中, 回复元素的先后顺序和命令发送的先后顺序一致。

    当客户端处于事务状态时, 所有传入的命令都会返回一个内容为 QUEUED 的状态回复(status reply), 这些被入队的命令将在 EXEC命令被调用时执行。

    事务中的错误

    使用事务可能会用到下面2种错误

     1.事务在执行exec之前,入列的命令可能会有错,如果说,命令语法错误

      2.命令在调用exec调用之后失败。比如事务命令可能处理了错误类型的键,把列表命令的键放到string中

     对于发生在exec执行之前的错误,客户端的做法是检查命令入列得到的值,如果命令是queue,则入列成功,否则,入列失败,如果入列失败,则大部分事务都会停止并取消这个事务

     对于发生在exec执行之后的错误,并没有对他们进行特别处理:即使事务中某个/某些事务发生错误,而其它的命令仍然会继续执行

     

    为什么Redis不支持回滚

    如果你有使用关系式数据的经验,那么“redis在事务失败时不进行回滚,而是继续执行余下的命令”这种做法可能会让你觉得有点奇怪

    以下是这种做法的优点:

      1.Redis命令只会因为错误的语法而失败(并且这些问题不能在入队时发现),或是命令用在了错误类型的键上面:也就是说,从实用性的角度来说,失败的命令是由编程错误造成的,而这些错误应该在开发的过程中被发现,而不应该出现在生产环境中

      2.因为不需要对回滚进行支持,所以Redis的内部保存简单且快速

    放弃事务

    当执行discard命令时,事务会被放弃,并且客户端会从事务状态中退出

    使用check-and-set操作实现乐观锁

    watch命令可以为redis事务提供check-and-set(cas)行为

    被watch的键会被监视,并会发觉这些键是否被改动。如果至少一个被监视的键在exec执行之前被修改了,那么整个事务都会被取消,exec返回空多条批量回复来表示事务已经失效

    举个例子,假设客户端有A和B 2个都读取了键原来的值,比如10,执行incr操作的时候,那么2个客户端都会将键的值设为11,但正确返回结果应该是12才对

    有了watch,我们就可以轻松地解决这类问题了:

    watch mykey

    val=get mykey

    val=val+1

    multi

    set mykey $val

    exec

    使用上面的代码,如果有了watch之后,exec执行之前,有其他客户端修改了mykey的值,那么当前客户端的事务就会失效。程序需要做的,就是不断重试这个操作,知道没有发生碰撞为止

    这种形式的锁被称为乐观锁,它是非常强大的锁机制。并且因为大多数情况下,不同的客户端会访问不同的值,碰撞的情况一般都很少,所以通常并不需要重试

    转载请注明原文地址: https://ju.6miu.com/read-963613.html

    最新回复(0)