ruby - 如何从 Ruby 中的 MULTI block 中的 Redis 读取数据?

标签 ruby transactions redis

我在 MULTI 事务中封装了一组复杂的 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' – 我该如何实现?

最佳答案

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

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

使用 WATCH 子句

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

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

这里的脚本有点复杂,因为 block 的内容可以为空,所以没有简单的方法可以知道交易是否已被取消,或者是否根本没有发生。当多 block 在所有情况下返回结果时通常更容易,除非交易被取消。

使用 Lua 服务器端脚本

使用 Redis 2.6 或更高版本,Lua scripts can be executed on the server .整个脚本的执行是原子的。它可以很容易地用 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 子句简单得多。

关于ruby - 如何从 Ruby 中的 MULTI block 中的 Redis 读取数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11300958/

相关文章:

Ruby IO#read 单次读取的最大长度

ruby-on-rails - 如何生成一个包含类中方法名称的文件?

c - "*((char*)-1) = ' x';"代码是什么意思?

.net - C# 事务中的事务

java - 如何实现Spring Boot Redis Multi-Tenancy ?

Redis.io 与 .Net 中的 Azure Redis 缓存

ruby - 只是为了好玩,我如何编写一个 ruby​​ 程序,一次缓慢地打印到 stdout 一个字符?

mysql - 在 Rails 项目中映射旧数据库列

具有 AUTO_INCREMENT primary id 的 MySQL 表在回滚后不释放数字

sql-server - SQL服务器事务