首页 > 编程知识 正文

redis解决重复消费,redis事务使用场景

时间:2023-05-04 07:00:54 阅读:159321 作者:4231

Redis事务提供了两个重要的保证

MULTI、EXEC、DISCARD和WATCH命令是Redis事务操作的基础。 他们可以让Redis在一个步骤中执行一系列指令,可以进行以下两个重要保证:

事务中的所有命令都将序列化并按顺序执行。 当一个客户端执行Redis事务时,它不会接收来自其他客户端的请求。 这将确保这些命令作为单独的独立操作运行。 的所有指令要么一起处理,要么全部不处理,所以Redis事务是原子的。 EXEC命令触发事务中所有命令的执行。 如果使用AOF,Redis将使用简单的write(2)系统级调用来确保事务写入磁盘。 但是,如果Redis服务崩溃或被系统管理员以某种强制方式杀死,则只有某些命令可能会写入磁盘。 Redis在重新启动时检测到这一点,并报告错误后退出。 redis-check-AOF工具允许您检查aof,删除不完整的事务,然后重新启动服务

从2.2开始,Redis可以通过其他形式(乐观锁定)确保上述两点。 详情在后面叙述。

使用方法

使用MULTI命令进入事务模式。 这个命令只需返回OK。 此时,用户可以发出多个一起执行的指令。 Redis暂时不执行这些命令,而是将其排队。 调用EXEC时,所有命令都将一次执行

相反,调用DISCARD命令会清除事务队列中的所有命令,然后事务结束。

以下示例是以原子方式增加的keys foo和bar。

Redis使用事务原子增量变量

综上所述,EXEC返回一个数组,其中包含事务中每个命令的执行结果,响应顺序与发出命令时的顺序相同。

如果Redis链接位于MULTI请求的上下文中,则所有命令的响应结果都为字符串QUEUED。 调用EXEC时,这些命令将一次执行。

错误

Redis事情可能会发生两种错误:

命令可能会排队失败。 例如,这可能是一个重要的环境问题,例如命令语法错误(错误的参数数量、错误的命令名称…)或内存不足。 调用EXEC后,某些命令可能会失败,例如在字符串上执行了列表命令操作。

第一个错误发生在EXEC命令之前,可以通过检查命令的返回值轻松发现。 如果返回值为QUEUED,则成功,否则失败。 Redis会返回错误。 如果在排队命令时发生错误,通常会终止事务。

从Redis 2.6.5开始,如果在命令排队时发生错误,Redis将拒绝执行EXEC并返回错误并自动丢弃事务。

在Redis 2.6.5之前的版本中,调用EXEC后,会排队并执行成功的命令,失败的命令将被忽略。

这个新规则使事务和管道的使用变得简单,整个事务一起发送,所有回复都被一次获取,从而节省了交互。

执行EXEC会执行所有命令,即使是错误的命令也会执行。

在以下示例中,事务已执行,其中一个命令失败。

事务成功,但存在命令错误

EXEC返回两个字符串。 一个是OK,另一个是-ERR,客户端决定如何处理此结果。

请注意,即使命令失败,队列中的其他命令也会运行。

发生语法错误时,尽快报告错误:

语法错误会立即返回错误

以上是INCR命令的语法错误,无法进入命令队列。

为什么Redis不支持回滚

Redis命令可能会在事务中失败,但Redis事务不会回滚,而是继续执行其馀的命令。 如果您了解关系数据库,则可能会感到奇怪,因为关系数据会在这种情况下回滚。

Redis这样做主要是因为:

只有在命令队列中发生无法检测到的语法错误时,Redis命令才会失败或向keys赋予类型错误数据。 这意味着所有这些都是程序性错误,可以在开发过程中检测并解决,在生产环境中很少出现。 因为不需要回滚,所以Redis的内部变得简单,执行速度变快。

放弃工作

DISCARD可以中止事务。 在这种情况下,不执行任何命令,客户端链接状态将恢复为正常状态。

Redis将丢弃事务

乐观锁定(check-and-set ) )。

WATCH命令为事务提供检查和设置(cas )行为。

WATCH可用于接收事务内队列中的命令。 如果在EXEC之前发现命令已更改,则整个事务将终止,EXEC将返回Null,指示用户事务失败。

例如,假设Redis尚未实现INCR命令,它会自动递增key。

那个代码可能是下面的:

如果在同一时间,只有一个客户端正在执行上述操作,则这些操作是可靠的。 但是,如果多个用户同时执行上述操作,其结果是

就是不可靠的了

我们可以使用 WATCH 来很好的解决这个问题:

使用以上的代码,当有另一个用户在我们调用WATCH 和 EXEC之间,修改了mykey的值val,那么这个事务就会失败。这种形式的锁称为乐观锁,是一种非常强大的锁。

WATCH 说明

WATCH 到底是什么意思呢? 这个命令使得 EXEC 命令的执行必须满足一个条件:如果被WATCH的 keys 没有一个被更改(但它们可以在事务中被修改),则执行事务;不然,就不会执行这个事务。(注意,如果你 WATCH了一个有生命周期的key,并且这个key过期了, EXEC 依然会执行)

WATCH 可以被多次调用。所有的WATCH 调用都会在 EXEC 调用之前起作用。WATCH可以接收任意多的key 。

当 EXEC 被调用后, 所有的keys都将UNWATCH,不管这个事务会不会终止。同样,当一个客户端链接关闭后, 一切都将UNWATCH。

可以使用UNWATCH (没有参数)命令来刷新所有被WATCH的keys。有时会这样操作,我们乐观地锁定了几个keys,因为可能我们需要执行一个事务来修改这些keys,但是在读取了keys的当前内容之后,我们不想继续处理了。那么这个时候,我们就可以调用UNWATCH。

用 WATCH 实现ZPOP

这是一个不错的示例,它阐述了如何使用WATCH 来产生新的原子操作,这个没有被Redis支持的ZPOP,这命令以原子的方式从一个有序集合中弹出较低的分数的值:

如果 EXEC 失败 (如,返回 Null ) 我们只需要重新执行这个操作即可。

参考文献:

https://baijiahao.baidu.com/s?id=1613631210471699441&wfr=spider&for=pc

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。