redis-06-事务

发布时间:2018-11-15  栏目:NoSQL  评论:0 Comments

事务

MULTI 、
EXEC 、
DISCARD 和
WATCH 是 Redis
事务相关的指令。事务可以同样次于施行多个命, 并且带有以下简单单至关重要的保:

  • 事情是一个独门的断操作:事务中的装有命令还见面序列化、按梯次地推行。事务在履行的长河遭到,不会见为外客户端发送来的授命请求所从断。

  • 工作是一个原子操作:事务中之一声令下要么全部深受实践,要么全部还非实施。

EXEC
命令担负触发并履行工作中的有所命令:

  • 万一客户端在使用 MULTI
    开启了一个事务之后,却为断线而没水到渠成实施
    EXEC
    ,那么事务中的保有命令还无见面为实施。
  • 单,如果客户端成功在拉开事务之后执行
    EXEC
    ,那么事务中之具备命令还见面受执行。

当用 AOF 方式开持久化的下, Redis 会使用单个 write(2)
命令将工作写副到磁盘中。

而是,如果 Redis
服务器因为某些原因让管理员杀死,或者被上某种硬件故障,那么可能只有有业务命令会让成功写副到磁盘中。

若是 Redis 在再度起动时意识 AOF
文件来了如此的问题,那么它们会脱离,并上报一个不当。

使用redis-check-aof程序可以修复这同题材:它见面移除 AOF
文件中莫完事务之音讯,确保服务器可以万事大吉起步。

自 2.2 版本开始,Redis 还可以通过乐观锁(optimistic lock)实现 CAS
(check-and-set)操作,具体信息要参见文档的晚半有的。

[TOC]

用法

MULTI
命令用于开启一个事情,它连接回到 OK
MULTI 执行后,
客户端可以延续朝服务器发送任意多漫漫命令, 这些命令不会见立马为执行,
而是被放一个班中, 当
EXEC指令于调用时,
所有班中之命才会给实践。

一派, 通过调用 DISCARD
, 客户端可以清空事务队列, 并放弃实行工作。

以下是一个工作例子, 它原子地充实了 foobar 两单键的值:

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

EXEC 命令的东山再起是一个频组,
数组中的每个元素还是实行工作中之命令所产生的复原。 其中,
回复元素的先后顺序和指令发送的先后顺序一致。

当客户端处于工作状态时, 所有传入的吩咐还见面回来一个情节呢 QUEUED
的状态回升(status reply), 这些吃入队的指令将当 EXEC
命令于调用时实施。

1 Redis事务简介

Redis可以一次执行多个命令,本质是如出一辙组命令的集合。一个作业中的有命令还见面序列化,按梯次地错行化执行要不见面被其他命令插入。

也就是说一次性顺序性排他性的履行同样组命令,和风俗习惯的RDBMS的事体有点类似。

  • 事情是一个单身的隔离操作:事务中之持有命令还见面序列化、按顺序地实行。事务在推行之长河中,不见面让另外客户端发送来之通令请求所于断。
  • 政工是一个原子操作:事务中的吩咐要么全部为实施,要么全部都未履行。

业务中的谬误

行使事务时可能会见惨遭上以下简单种错误:

  • 政工在执行 EXEC
    之前,入队的吩咐可能会见拧。比如说,命令可能会见生出语法错误(参数数量错误,参数号称错误,等等),或者其他还要紧的荒唐,比如内存不足(如果服务器使用
    maxmemory 设置了最为充分外存限制的讲话)。
  • 令可能在 EXEC
    调用之后失败。举个例子,事务中之一声令下可能处理了错误类型的键,比如用列表命令用当了字符串键上面,诸如此类。

于发生在 EXEC
执行前的谬误,客户端以前的做法是检查命令入队所得的返回值:如果命令入队时回来
QUEUED
,那么入队成功;否则,就是入队失败。如果生发号施令于入队时失败,那么大部分客户端都见面停止并撤回这业务。

然而,从 Redis 2.6.5
开始,服务器会针对命令入队失败的事态开展记录,并于客户端调用
EXEC
命令时,拒绝执行并活动放弃这业务。

每当 Redis 2.6.5 以前, Redis
只实行工作中那些入队成功之一声令下,而忽视那些入队失败的命令。
而初的处理方式则让在工艺流程(pipeline)中富含事务变得简单,因为发送业务和朗诵博事务的复都只待同服务器进行一软通讯。

关于那些在 EXEC
命令执行下所产生的荒唐, 并没有对准其进行特别处理:
即使工作中发出有/某些命令在实施时生了错,
事务中之任何命令还会继续执行。

自从商事的角度来拘禁这个题目,会重复易理解一些。 以下例子中,
LPOP 命令的实施将出错,
尽管调用它的语法是对的:

Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
MULTI
+OK
SET a 3
abc
+QUEUED
LPOP a
+QUEUED
EXEC
*2
+OK
-ERR Operation against a key holding the wrong kind of value

EXEC
返回两修bulk-string-reply:
第一条凡 OK ,而第二久是 -ERR
至于怎样用当的办法来表示事情中之失实, 则是由于客户端好说了算的。

极端要的凡记忆犹新这样平等条, 即使工作中起某条/某些命令执行破产了,
事务队列中之任何命令还会继续执行 —— Redis 不见面告一段落实施工作中之通令。

以下例子展示的是另一样栽情景, 当命令在入队时生错误,
错误会应声吃归给客户端:

MULTI
+OK
INCR a b c
-ERR wrong number of arguments for 'incr' command

盖调用 INCR
命令的参数格式不正确, 所以这个
INCR 命令入队失败。

2 和工作相关的命

怎 Redis 不支持回滚(roll back)

若是你生使用关系式数据库的经历, 那么 “Redis
在作业失败时未进行回滚,而是继续执行余下的通令”这种做法可能会见吃你看有点意外。

以下是这种做法的优点:

  • Redis
    命令就见面坐错误的语法而破产(并且这些问题未可知以入队时发现),或是命令用当了错类型的键上面:这也算得,从实用性的角度来说,失败的一声令下是由编程错误致的,而这些不当应于付出之经过被让察觉,而无应出现于生产条件受到。
  • 为不需对回滚进行支撑,所以 Redis 的里边可以保简单且高效。

勇于观点看 Redis 处理事务的做法会发生 bug , 然而要小心的是,
在通常状态下, 回滚并无克解决编程错误带来的问题。 举个例,
如果你本想通过 INCR
命令将键的值长 1 , 却无小心加上了 2 , 又或对错类型的键执行了
INCR ,
回滚是没办法处理这些情形的。

2.1 multi

拖欠令开启一个事务,它总是回到 OK.

相当于session.begainTransaction().

放弃工作

当执行 DISCARD 命令时,
事务会让放弃, 事务队列会为清空, 并且客户端会从事情状态被剥离:

> SET foo 1
OK
> MULTI
OK
> INCR foo
QUEUED
> DISCARD
OK
> GET foo
"1"

2.2 exec

行一个事务块内之有着命令。

相当于session.commit().

同时exec之前的监控所还于收回了。

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

WATCH 命令可以为 Redis
事务提供 check-and-set (CAS)行为。

被 WATCH
的键会被监视,并会意识这些键是否给改过了。 如果发最少一个吃监视的键在
EXEC 执行前让改动了,
那么任何业务都见面为撤, EXEC
返回nil-reply来表示事情都失败。

选举个例证, 假设我们用原子性地为有值进行增 1 操作(假设
INCR 不存在)。

首先我们恐怕会见如此做:

val = GET mykey
val = val + 1
SET mykey $val

面的斯实现以单出一个客户端的当儿可以履得格外好。 但是,
当多个客户端同时针对同个键进行这样的操作时,
就会见生出竞争条件。举个例子, 如果客户端 A 和 B 都读取了键本来的价, 比如
10 , 那么零星只客户端都见面将键的值设为 11 , 但正确的结果应是 12 才对。

有了 WATCH ,
我们就算可以轻松地解决就类似题目了:

WATCH mykey
val = GET mykey
val = val + 1
MULTI
SET mykey $val
EXEC

运方面的代码, 如果在 WATCH
执行后, EXEC 执行前,
有另外客户端修改了 mykey 的价, 那么当前客户端的政工就会破产。
程序需要举行的, 就是不断重试这个操作, 直到没有起打为止。

这种样式的吊被名乐观锁, 它是一律栽非常强大的锁机制。
并且因为大部分情形下, 不同之客户端会访问不同的键,
碰撞的状态一般都格外少, 所以通常并不需要进行重试。

2.3 discard

收回事务。

相当于session.rollback().

了解 WATCH

WATCH 使得
EXEC 命令需要来格地尽:
事务只能在拥有被监视键都没有叫改动的前提下执行,
如果这个前提不克满足的说话,事务就未会见吃执行。
刺探再多->

WATCH 命令可以给调用多次。
对键的监从 WATCH
执行后开始生效, 直到调用
EXEC 为止。

用户还得当么 WATCH
命令中监任意多个键, 就像这样:

redis> WATCH key1 key2 key3
OK

当 EXEC 被调用时,
不管事务是否成实施, 对所有键的监都见面被撤除。

另外, 当客户端断开连接时, 该客户端对键的监视也会见为撤销。

行使无参数的 UNWATCH
命令可以手动取消对所有键的监。 对于有索要改变多单键的事情,
有时候程序需要而针对多独键进行加锁,
然后检查这些键的手上价值是否符合程序的要求。 当值达不顶要求时, 就好利用
UNWATCH
命令来取消时对键的监视, 中途放弃是事情, 并等待事务之下次尝试。

2.4 watch/unwatch

WATCH的键会被监视。如果起起码一个深受监视的键在
EXEC
执行前让改了, 那么任何业务都见面受注销,
EXEC
返回nil-reply来表示事情都失败。

相对的,UNWATCH一声令下用来取消针对所有key的监视.

3 事务操作示例

3.1 正常了的业务

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> MULTI # 开启事务
OK # 该命令总是返回OK
127.0.0.1:6379> set k1 v1
QUEUED # 入队,等待exec
127.0.0.1:6379> get k1
QUEUED # get操作同样是入队
127.0.0.1:6379> set k2 v2
QUEUED # 入队
127.0.0.1:6379> EXEC
1) OK # set k1 v1 的返回值
2) "v1" # get k1 的返回值
3) OK # set k2 v2 的返回值
127.0.0.1:6379> keys *
1) "k1"
2) "k2"
127.0.0.1:6379>  

3.2 正常取消的事务

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> set k1 v1 # 先准备个历史数据
OK
127.0.0.1:6379> get k1
"v1"
127.0.0.1:6379> MULTI # 开启事务
OK
127.0.0.1:6379> set k1 v11111 # 修改k1的值为v11111
QUEUED
127.0.0.1:6379> get k1
QUEUED
127.0.0.1:6379> set k2 v222
QUEUED
127.0.0.1:6379> DISCARD # 取消事务
OK
127.0.0.1:6379> keys *
1) "k1" # set k2 v2 被回滚了
127.0.0.1:6379> get k1
"v1" # set k1 v11111 被回滚了
127.0.0.1:6379>  

3.3 一个老鼠害一锅汤

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> MULTI # 开启事务
OK
127.0.0.1:6379> set k1 v1 
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> a-error-cmd # 故意乱写一通
(error) ERR unknown command 'a-error-cmd'
127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> exec # 提交事务
# 上面手动制造的a-error-cmd导致的
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> keys *
(empty list or set) # 一条也没有生效
127.0.0.1:6379>  

3.4 对的实施错的回滚

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> get k1
QUEUED
127.0.0.1:6379> INCRBY k1 10
QUEUED
127.0.0.1:6379> get k1
QUEUED
127.0.0.1:6379> exec
1) OK
2) "v1"
3) (error) ERR value is not an integer or out of range
4) "v1"
127.0.0.1:6379>  

以及上一个演示中之荒谬不同之凡:

  • 此的incrby相当于Java中的运转时非常,只有当真运行时才能够窥见的左(只回滚错误的一声令下)
  • 若达标一个示范中伪造的命令a-error-cmd相当于Java中当静态编译时即便得确定的荒谬(全部回滚)

3.5 watch/unwatch示例

此地的个人信用卡底以身作则来自尚硅谷教学视频:

  • 正常的watch以身作则—两画金额之改观在跟一个工作内发生

127.0.0.1:6379> set balance 100
OK
127.0.0.1:6379> set debt 0
OK
127.0.0.1:6379> WATCH balance
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> DECR balance
QUEUED
127.0.0.1:6379> INCR debt
QUEUED
127.0.0.1:6379> exec # 监控锁也被取消了
1) (integer) 99
2) (integer) 1
127.0.0.1:6379>  
  • 被中止了之watch

图片 1

watch

3.6 总结

  • Watch指令,类似乐观锁,事务提交时,如果Key的价都受别的客户端转移(比如某个list已被别的客户端push/pop过了)整个业务队列都未见面被执行.

  • 经过WATCH命令在业务执行前监控了大半个Keys,倘若在WATCH之后有其他Key的价值发生了变通,

    EXEC命令执的作业都将为放弃,同时返回Nullmulti-bulk应答以通知调用者事务执行失败.

4 Redis事务的总

  • 政工相关的指令

    • multi被事务
    • 打开事务后,提交的授命不见面于随即执行,而是入队
    • exec提交业务,执行命令
    • discard回滚放弃工作
  • 政工之特色

    • 作业中的富有命令还见面序列化、按梯次地执行。事务在实施的过程中,不见面于别客户端发送来之吩咐请求所不通
    • 列中之一声令下没有交到之前还不见面实际的叫执行
    • redis同一个政工中假如起平等长命令执行破产,正确的命还会于实施,不见面回滚(不包原子性)

参考资料

  • 尚硅谷思维导图
  • https://redis.io/documentation
  • http://www.redis.cn/documentation.html

留下评论

网站地图xml地图