如何从 Ruby 中的 MULTI 块内的 Redis 读取? [英] How can I read from Redis inside a MULTI block in Ruby?

查看:25
本文介绍了如何从 Ruby 中的 MULTI 块内的 Redis 读取?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 MULTI 事务中封装了一组复杂的 Redis 命令,但事务中的逻辑取决于 Redis 中已有的值.但是事务中的所有读取似乎都返回 nil

I'm encapsulating a complicated set of Redis commands in a MULTI transaction, but the logic in the transaction depends on values already in Redis. But all reads within a transaction seem to return nil

这是一个演示问题的示例:

Here's an example that demonstrates the problem:

[Dev]> $redis.set("foo", "bar")
=> "OK"
[Dev]> $redis.multi{ $redis.set("foo", "baz") if $redis.get("foo") == "bar" }
=> ["bar"]
[Dev]> $redis.get("foo")
=> "bar"

显然我希望最后一个返回值是 'baz' - 我怎样才能做到这一点?

Obviously I want the last return value to be 'baz' – how can I achieve this?

推荐答案

您不能,因为所有命令(包括 get)实际上都是在 exec 时执行的.在这种情况下,get 命令只返回未来对象,而不是实际值.

You cannot, since all commands (including get) are actually executed at exec time. In this situation, the get command only returns a future object, not the actual value.

有两种方法可以实现这种交易.

There are two ways to implement such transaction.

使用 WATCH 子句

watch 子句用于防止并发更新.如果在 watch 和 multi 子句之间更新了变量的值,则不会应用 multi 块中的命令.由客户决定再次尝试交易.

The watch clause is used to protect against concurrent updates. If the value of the variable is updated between the watch and multi clause, then the commands in the multi block are not applied. It is up to the client to attempt the transaction another time.

loop do
    $redis.watch "foo" 
    val = $redis.get("foo")
    if val == "bar" then
        res = $redis.multi do |r|
            r.set("foo", "baz") 
        end
        break if res
    else
        $redis.unwatch "foo"
        break
    end
end

这里的脚本有点复杂,因为块的内容可以是空的,所以没有简单的方法知道交易是被取消了,还是根本没有发生.除非交易被取消,否则多块在所有情况下都返回结果通常更容易.

Here the script is a bit complex because the content of the block can be empty, so there is no easy way to know whether the transaction has been cancelled, or whether it did not take place at all. It is generally easier when the multi block returns results in all cases except if the transaction is cancelled.

使用 Lua 服务器端脚本

使用 Redis 2.6 或更高版本,Lua 脚本可以在服务器上执行.整个脚本的执行是原子的.它可以很容易地在 Ruby 中实现:

With Redis 2.6 or better, Lua scripts can be executed on the server. The execution of the whole script is atomic. It can be easily implemented in Ruby:

cmd = <<EOF
    if redis.call('get',KEYS[1]) == ARGV[1] then
       redis.call('set',KEYS[1],ARGV[2] )
    end
EOF
$redis.eval cmd, 1, "foo", "bar", "baz"

这通常比使用 WATCH 子句简单得多.

This is typically much simpler than using WATCH clauses.

这篇关于如何从 Ruby 中的 MULTI 块内的 Redis 读取?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆