• Redis事务


    1. Redis事务是什么

    Redis中的事务提供了一种将多个命令请求打包,然后一次性、顺序性执行多个命令的机制,并且在事务指向期间,服务器不会中断事务而改去执行其他客户端的命令请求,它会将事务中的所有命令都执行完毕,然后才去处理其他客户端的请求。

    2. Redis事务的实现

    Redis事务的实现需要用到 MULTI  EXEC 两个命令,事务开始的时候先向Redis服务器发送 MULTI 命令,然后依次发送需要在本次事务中处理的命令,最后再发送 EXEC 命令表示事务命令结束。

    2.1 正常执行

    通过MULTI  EXEC 两个命令演示正常的事务执行生效过程。

    从输出中可以看到,当输入 MULTI 命令后,服务器返回OK表示事务开始成功,然后依次输入需要在本次事务中执行的所有命令,每次输入一个命令服务器并不会马上执行,而是返回”QUEUED”,这表示命令已经被服务器接受并且暂时保存起来,最后输入EXEC命令后,本次事务中的所有命令才会被依次执行,可以看到最后服务器一次性返回了三个OK,这里返回的结果与发送的命令是按顺序一一对应的,这说明这次事务中的命令全都执行成功了。

    如果客户端在发送EXEC命令之前断线了,则服务器会清空事务队列,事务中的所有命令都不会被执行。而一旦客户端发送了EXEC命令之后,事务中的所有命令都会被执行,即使此后客户端断线也没关系,因为服务器已经保存了事务中的所有命令。

    2.2 全体连坐

    语法错误会使得事务中的命令全部不执行。

    语法错误表示命令不存在或者参数错误,这种情况需要区分Redis的版本,2.6.5之后的版本会忽略这个事务中的所有命令,都不执行。Redis 2.6.5之前的版本会忽略错误的命令,执行其他正确的命令。下面是我使用redis2.4.5测试的截图。

    2.3 冤头债主

    运行错误会使得事务跳过有错的语句,仅执行无报错的任务。

     

    运行错误表示命令在执行过程中出现错误,比如给非数字值增一、用GET命令获取一个散列表类型的键值等。这种错误在命令执行之前Redis是无法发现的,所以在事务里这样的命令会被Redis接受并执行。如果事务里有一条命令执行错误,其他命令依旧会执行(包括出错之后的命令)。

    2.4 WATCH 监控

    WATCH命令是一个乐观锁,它可以在EXEC命令执行之前,监视任意数量的数据库键,并在EXEC执行时,检查被监视的键是否至少有一个已经被修改过了,如果是的话,服务器将拒绝执行事务,并向客户端返回执行失败的nil回复。

    EXEC命令执行完之后被监控的键会自动被UNWATCH,另外UNWATCH命令也可以在WATCH命令执行之后、MULTI命令执行之前取消对某个键的监控。

    2.5 放弃事务

    放弃事务使用 DISCARD 命令,DISCARD命令可以在 MULTI 命令执行之后,EXEC 命令执行之前取消 WATCH 命令并清空事务队列,然后从事务状态中退出。

     

    3. 为什么Redis不支持回滚

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

    以下是这种做法的优点:

    • Redis 命令只会因为错误的语法而失败(并且这些问题不能在入队时发现),或是命令用在了错误类型的键上面:这也就是说,从实用性的角度来说,失败的命令是由编程错误造成的,而这些错误应该在开发的过程中被发现,而不应该出现在生产环境中。
    • 因为不需要对回滚进行支持,所以 Redis 的内部可以保持简单且快速。

    有种观点认为 Redis 处理事务的做法会产生 bug , 然而需要注意的是, 在通常情况下, 回滚并不能解决编程错误带来的问题。 举个例子, 如果你本来想通过 INCR 命令将键的值加上 1 , 却不小心加上了 2 , 又或者对错误类型的键执行了 INCR , 回滚是没有办法处理这些情况的。

    鉴于没有任何机制能避免程序员自己造成的错误, 并且这类错误通常不会在生产环境中出现, 所以 Redis 选择了更简单、更快速的无回滚方式来处理事务

    4. Redis事务的总结

    Redis事务实现分为三个阶段:

    • 开启:以MULTI开始一个事务。
    • 入队:将多个命令入队到事务中,接到这些命令并不会立即执行,而是放到等待执行的事务队列里面。
    • 执行:由EXEC命令触发事务。

    Redis事务的三个特性:

    • 单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
    • 没有隔离级别的概念:队列中的命令没有提交之前都不会实际的被执行,因为事务提交前任何指令都不会被实际执行,也就不存在”事务内的查询要看到事务里的更新,在事务外查询不能看到”的问题。
    • 不保证原子性:redis同一个事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚。

      

  • 相关阅读:
    LeetCode 485. Max Consecutive Ones
    LeetCode 367. Valid Perfect Square
    LeetCode 375. Guess Number Higher or Lower II
    LeetCode 374. Guess Number Higher or Lower
    LeetCode Word Pattern II
    LeetCode Arranging Coins
    LeetCode 422. Valid Word Square
    Session 共享
    java NIO
    非阻塞IO
  • 原文地址:https://www.cnblogs.com/zjfjava/p/10994026.html
Copyright © 2020-2023  润新知