Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Ruby中的多块中读取Redis?_Ruby_Transactions_Redis - Fatal编程技术网

如何在Ruby中的多块中读取Redis?

如何在Ruby中的多块中读取Redis?,ruby,transactions,redis,Ruby,Transactions,Redis,我在多事务中封装了一组复杂的Redis命令,但事务中的逻辑取决于Redis中已有的值。但事务中的所有读取似乎都返回nil 下面的示例演示了问题: [Dev]> $redis.set("foo", "bar") => "OK" [Dev]> $redis.multi{ $redis.set("foo", "baz") if $redis.get("foo") == "bar" } => ["bar"] [Dev]> $redis.get("foo") => "b

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

下面的示例演示了问题:

[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'
——我如何实现这一点?

正如Sergio在他的评论中所说,您不能选择性地执行Redis中那样的
块。见:

要么处理所有命令,要么不处理任何命令

但是,您可以使用check和set实现乐观锁定(伪代码):

使用
WATCH
,仅当监视的密钥未更改时,才会执行事务。如果更改了watch键,则执行将失败,您可以重试


另一种可能是使用脚本功能,但这仅在2.6候选版本中可用。

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

实现这种事务有两种方法

使用WATCH子句

watch子句用于防止并发更新。如果变量的值在watch和multi子句之间更新,则不会应用multi块中的命令。由客户机在另一时间尝试该事务

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
这里的脚本有点复杂,因为块的内容可以是空的,所以没有简单的方法知道事务是否已被取消,或者它是否根本没有发生。除非交易被取消,否则在所有情况下,当多块返回结果时通常更容易

使用Lua服务器端脚本

使用Redis 2.6或更高版本。整个脚本的执行是原子的。它可以在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"

cmd=恐怕你不能这么做。使用Lua而不是WATCH命令,或者相反,是否有性能上的折衷?Lua更快,因为:1-它避免了客户端和redis服务器之间的多次往返;2-您不必通过循环来掩盖潜在的故障,那么Lua的缺点是它在脚本期间会阻止redis接收额外的命令,对吗?是的,任何Lua脚本都是以原子方式执行的-在处理Lua脚本时,不能处理任何其他命令。
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"