好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

详细了解Redis中的事务

本篇文章带大家详细了解一下Redis中的事务。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。

【相关推荐:Redis视频教程】

相关命令 命令 格式 作用 返回结果 WATCH WATCH key [key ...] 将给出的 Keys 标记为 监测态 ,作为事务执行的条件 always OK. UNWATCH UNWATCH 清除事务中 Keys 的 监测态 ,如果调用了 EXEC or DISCARD ,则没有必要再手动调用 UNWATCH always OK. MULTI MULTI 显式 开启 redis事务 ,后续 commands 将排队,等候使用 EXEC 进行原子执行 always OK. EXEC EXEC 执行事务中的 commands 队列,恢复连接状态。如果 WATCH 在之前被调用,只有 监测 中的 Keys 没有被修改,命令才会被执行,否则停止执行(详见下文, CAS机制 ) 成功: 返回数组 —— 每个元素对应着原子事务中一个 command 的返回结果;
失败: 返回 NULL ( Ruby 返回 `nil` ); DISCARD DISCARD 清除事务中的 commands 队列,恢复连接状态。如果 WATCH 在之前被调用, 释放 监测 中的 Keys always OK.

注意:

------ MULTI , EXEC , DISCARD 才是 显式 开启并控制事务的常用命令,可类比 关系型数据库 中的 BEGAIN , COMMIT , ROLLBACK (事实上,差距很大);

------ WATCH 命令的使用是为了解决 事务并发 产生的 不可重复读 和 幻读 的问题(简单理解为给 Key加锁 );

Redis事务

MULTI, EXEC, DISCARD and WATCH 是Redis事务的基础。 用来显式开启并控制一个事务,它们允许在一个步骤中执行一组命令 。并提供两个重要的保证:

事务中的所有命令都会被序列化并按顺序执行。在执行Redis事务的过程中,不会出现由另一个客户端发出的请求。这保证 命令队列 作为一个单独的原子操作被执行。 队列中的命令要么全部被处理,要么全部被忽略。EXEC命令触发事务中所有命令的执行,因此,当客户端在事务上下文中失去与服务器的连接, 如果发生在调用MULTI命令之前,则不执行任何 commands ; 如果在此之前EXEC命令被调用,则所有的 commands 都被执行。

同时,redis使用AOF(append-only file),使用一个额外的 write操作 将事务写入磁盘。如果发生宕机,进程奔溃等情况,可以使用redis-check-aof tool 修复append-only file,使服务正常启动,并恢复部分操作。

用法

使用 MULTI 命令 显式开启 Redis事务。 该命令总是以OK回应。 此时用户可以发出多个命令,Redis不会执行这些命令,而是将它们排队 。 EXEC 被调用后,所有的命令都会被执行。而调用 DISCARD 可以 清除 事务中的 commands队列 并 退出事务 。

以下示例以原子方式,递增键foo和bar。
>MULTI
OK
>INCR foo
QUEUED
>INCR bar
QUEUED
>EXEC
1)(整数)1
2)(整数)1

从上面的命令执行中可以看出, EXEC 返回一个 数组 , 其中每个元素都是事务中单个命令的返回结果,而且顺序与命令的发出顺序相同 。 当Redis连接处于 MULTI 请求的上下文中时,所有命令将以 字符串QUEUED ( 从Redis协议的角度作为状态回复发送 )作为回复,并在 命令队列 中排队。只有EXEC被调用时,排队的命令才会被执行,此时才会有 真正的返回结果 。

事务中的错误

事务期间,可能会遇到两种命令错误:

在调用 EXEC 命令之前出现错误( COMMAND 排队失败)。 例如,命令可能存在 语法错误 (参数数量错误,错误的命令名称...); 或者可能存在 某些关键条件 ,如内存不足的情况(如果服务器使用 maxmemory 指令做了 内存限制 )。

客户端会在 EXEC 调用之前检测第一种错误 。 通过检查排队命令的 状态回复 (***注意:这里是指 排队 的 状态回复 ,而不是 执行结果 ***),如果命令使用 QUEUED 进行响应,则它已正确排队,否则Redis将返回错误。如果排队命令时发生错误,大多数客户端将 中止该事务并清除命令队列 。然而:

在 Redis 2.6.5之前 ,这种情况下,在 EXEC 命令调用后,客户端会执行命令的子集(成功排队的命令)而忽略之前的错误。 从 Redis 2.6.5开始 ,服务端会记住在累积命令期间发生的错误,当 EXEC 命令调用时, 将拒绝执行事务,并返回这些错误,同时自动清除命令队列 。 示例如下:
>MULTI
+OK
>INCR a b c
-ERR wrong number of arguments for 'incr' command

这是由于 INCR 命令的语法错误,将在调用 EXEC 之前被检测出来,并终止事务(version2.6.5+)。

在调用 EXEC 命令之后出现错误。 例如,使用 错误的值 对某个 key 执行操作(如针对 String 值调用 List 操作)

EXEC 命令执行之后发生的错误并不会被特殊对待 : 即使事务中的某些命令执行失败,其他命令仍会被正常执行 。

示例如下:
>MULTI
+OK
>SET a 3
+QUEUED
>LPOP a
+QUEUED
>EXEC
*2
+OK
-ERR Operation against a key holding the wrong kind of value
EXEC 返回一个包含两个元素的字符串数组,一个元素是 OK ,另一个是 -ERR…… 。 能否将错误合理的反馈给用户这取决于 客户端library (如: Spring-data-redis.redisTemplate )的自身实现。 需要注意的是, 即使命令失败,队列中的所有其他命令也会被处理----Redis不会停止命令的处理 。

Redis事务不支持Rollback( 重点 )

事实上 Redis命令 在事务执行时可能会失败,但仍会继续 执行剩余命令 而不是 Rollback (事务回滚)。如果你使用过 关系数据库 ,这种情况可能会让你感到很奇怪。然而针对这种情况具备很好的解释:

Redis命令 可能会执行失败,仅仅是由于错误的语法被调用(命令排队时检测不出来的错误),或者使用错误的数据类型操作某个 Key : 这意味着,实际上失败的命令都是编程错误造成的,都是开发中能够被检测出来的,生产环境中不应该存在。(这番话,彻底甩锅,“都是你们自己编程错误,与我们无关”。) 由于不必支持 Rollback , Redis 内部简洁并且更加高效。

“ 如果错误就是发生了呢? ”这是一个 反对Redis 观点的 争论 。然而应该指出的是,通常情况下,回滚并不能挽救编程错误。 鉴于没有人能够挽救程序员的错误 ,并且 Redis命令 失败所需的错误类型不太可能进入生产环境,所以我们选择了不支持错误回滚(Rollback)这种更简单快捷的方法。

清除命令队列

DISCARD 被用来中止事务。事务中的所有命令将不会被执行,连接将恢复正常状态。

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

更多编程相关知识,请访问:编程视频!!

以上就是详细了解Redis中的事务的详细内容!

查看更多关于详细了解Redis中的事务的详细内容...

  阅读:55次