6

我想用 StackExchange.Redis 做一个基本的手表。如果在事务期间更改了密钥,则会失败。

StackExchange.Redis 很好地将其抽象为“条件”api,它支持“等于”和“存在”的概念。

这真的很好,但我想做一些类似“不变”的事情。我可能会遗漏一些东西,但在这一点上我还不清楚如何做到这一点。

是否可以执行以下操作:

var transaction = redis.CreateTransaction();
transaction.AddCondition(Condition.StringUnchanged("key")); //the API here could maybe be simplified
var val = transaction.StringGet("key"); //notably, this is not async because you would have to get the result immediately - it would only work on watched keys
transaction.StringSetAsync("key", val + 1);
transaction.Execute();

甚至可能是更好的版本(可以做同样的事情):

var transaction = redis.CreateTransaction();
var val = transaction.Watch("key"); //this would return the value!
transaction.StringSetAsync("key", val + 1);
transaction.Execute();

目前,我理解这样做的唯一方法是按照以下方式做一些事情:

var val = redis.StringGet("key");
var transaction = redis.CreateTransaction();
transaction.AddCondition(Condition.StringEqual("key", val));
transaction.StringSetAsync("key", val + 1);
transaction.Execute();

从阅读 SE.Redis 代码的尝试中,我理解翻译成类似的东西(不确定这有多准确):

val = GET key
WATCH key
MULTI
val = val + 1
SET key $val
checkVal = GET key
(then if checkVal != val:) UNWATCH
(otherwise:) EXEC

我仍在学习更多关于 Redis 的知识,但我不太确定这样做有什么好处。您不希望最终结果更像这样吗?:

WATCH key
MULTI
val = GET key
val = val + 1
SET key $val
EXEC

还是 SE.Redis 的工作方式不可能做到这一点?

4

1 回答 1

3

没有直接公开的原因WATCH是因为 SE.Redis 被设计为在单个连接上多路复用来自不同调用堆栈的命令。这使得任何事务工作都必须得到非常严格的管理。

我不清楚“不变”本身的目的是什么,没有与一些已知值进行比较 - 否则你只是在创造一个竞争条件。肯定可以添加对它的支持,但我真的很想先了解预期的用例。你可以解释吗?


重新编辑;您首选的示例(最后一个)根本不可能使用 redis - 与 SE.Redis 无关;如果您在 aGET内执行MULTI操作,则在完成之前您不会得到答案EXEC- 所以您不可能使用SET:它尚不可用中的值。

如果它不是用于多路复用,您可以重新排序您的第二个示例(基于 SE.Redis 所做的):

WATCH key
val = GET key
MULTI
val = val + 1
SET key $val
EXEC

这是 的典型用法WATCH:您提前查看要查询的内容,然后您知道{key}在此循环期间没有更改(或者至少,事务将中止;没有不一致的状态)。但是,WATCH 多路复用器不能很好地发挥作用,这就是为什么 SE.Redis 强制您在事务之前获取值的路径,然后允许您比较值以断言它是不变的。结果相同;方法略有不同,但它是多路复用器安全的。有关该主题的更多信息,请参见此处

于 2014-11-06T22:06:38.497 回答