您好,欢迎访问一九零五行业门户网

redis防坑指南——事务

相关命令介绍:
(学习视频分享:redis视频教程)
注意:
------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。
>multiok>incr fooqueued>incr barqueued>exec1)(整数)12)(整数)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 1ok> multiok> incr fooqueued> discardok> get foo"1"
相关推荐:redis数据库教程
以上就是redis防坑指南——事务的详细内容。
其它类似信息

推荐信息