zoukankan      html  css  js  c++  java
  • Redis-事务

    1.1 为什么要用事务

      我们知道 Redis 的单个命令是原子性的(比如 get set mget mset),如果涉及到多个命令的时候,需要把多个命令作为一个不可分割的处理序列,就需要用到事务。
    例如我们之前说的用 setnx 实现分布式锁,我们先 set,然后设置对 key 设置 expire,防止 del 发生异常的时候锁不会被释放,业务处理完了以后再 del,这三个动作我们就希
    望它们作为一组命令执行。
      Redis 的事务有两个特点:
    1、按进入队列的顺序执行。
    2、不会受到其他客户端的请求的影响。
      Redis 的事务涉及到四个命令:
    multi(开启事务),exec(执行事务),discard(取消事务),watch(监视)。

    1.2 事务的用法

      案例场景:tom 和 mic 各有 1000 元,tom 需要向 mic 转账 100 元。tom 的账户余额减少 100 元,mic 的账户余额增加 100 元。
      127.0.0.1:6379> set tom 1000 
      OK
      127.0.0.1:6379> set mic 1000 
      OK
      127.0.0.1:6379> multi 
      OK
      127.0.0.1:6379> decrby tom 100 
      QUEUED 
      127.0.0.1:6379> incrby mic 100 
      QUEUED 
      127.0.0.1:6379> exec
      1) (integer) 900 
      2) (integer) 1100 
      127.0.0.1:6379> get tom 
    "900" 127.0.0.1:6379> get mic
    "1100"
      通过 multi 的命令开启事务。事务不能嵌套,多个 multi 命令效果一样。multi 执行后,客户端可以继续向服务器发送任意多条命令, 这些命令不会立即被执行,
    而是被放到一个队列中, 当 exec 命令被调用时, 所有队列中的命令才会被执行。
      通过 exec 的命令执行事务。如果没有执行 exec,所有的命令都不会被执行。如果中途不想执行事务了,怎么办?可以调用 discard 可以清空事务队列,放弃执行。
    multi 
    set k1 1 
    set k2 2 
    set k3 3 
    discard

    1.3 watch 命令

      在 Redis 中还提供了一个 watch 命令。它可以为 Redis 事务提供 CAS 乐观锁行为(Check and Set / Compare andSwap),也就是多个线程更新变量的时候,
    会跟原值做比较,只有它没有被其他线程修改的情况下,才更新成新的值。
      我们可以用 watch 监视一个或者多个 key,如果开启事务之后,至少有一个被监视key 键在 exec 执行之前被修改了, 那么整个事务都会被取消(key 提前过期除外)。
    可以用 unwatch 取消。

    1.4 事务可能遇到的问题

      我们把事务执行遇到的问题分成两种,一种是在执行 exec 之前发生错误,一种是在执行 exec 之后发生错误。

    1.4.1 在执行 exec 之前发生错误

      比如:入队的命令存在语法错误,包括参数数量,参数名等等(编译器错误)。
    127.0.0.1:6379> multi 
    OK
    127.0.0.1:6379> set gupao 666 
    QUEUED 
    127.0.0.1:6379> hset qingshan 2673 
    (error) ERR wrong number of arguments for 'hset' command 
    127.0.0.1:6379> exec 
    (error) EXECABORT Transaction discarded because
    在这种情况下事务会被拒绝执行,也就是队列中所有的命令都不会得到执行。

    1.4.2 在执行 exec 之后发生错误

      比如,类型错误,比如对 String 使用了 Hash 的命令,这是一种运行时错误。
    127.0.0.1:6379> multi 
    OK
    127.0.0.1:6379> set k1 1 
    QUEUED 
    127.0.0.1:6379> hset k1 a b
    QUEUED 
    127.0.0.1:6379> exec 
    1) OK 
    2) (error) WRONGTYPE Operation against a key holding the wrong kind of value 
    127.0.0.1:6379> get k1 
    "1"
      最后我们发现 set k1 1 的命令是成功的,也就是在这种发生了运行时异常的情况下,只有错误的命令没有被执行,但是其他命令没有受到影响。
    这个显然不符合我们对原子性的定义,也就是我们没办法用 Redis 的这种事务机制来实现原子性,保证数据的一致。


  • 相关阅读:
    如何通过关键词匹配统计其出现的频率
    好玩的SQL
    如何用Dummy实例执行数据库的还原和恢复
    如何查找特定目录下最大的文件及文件夹
    《Administrator's Guide》之Managing Memory
    Oracle如何实现从特定组合中随机读取值
    如何用分析函数找出EMP表中每个部门工资最高的员工
    Oracle之DBMS_RANDOM包详解
    RAC碎碎念
    如何利用Direct NFS克隆数据库
  • 原文地址:https://www.cnblogs.com/talkingcat/p/13815180.html
Copyright © 2011-2022 走看看