总之,我正在尝试调用ITransaction.SetPopAsync(...)
并执行其他写操作,作为基础MULTI
Redis原子操作的一部分。
我尝试执行SetPopAsync(...)
调用Task.ContinueWith
的延续,并在回调中执行所谓的其他写操作,但当我发现这些操作在执行后执行时我感到很惊讶基础MULTI
操作结束(即ITransaction.ExecuteAsync()
完成时)。
也许我错了,但我觉得只有当我将一个LUA脚本加载到Redis并且我用C#调用它时,才能完成这个原子操作。
我的案例中是否还有其他解决方案可以在C#和StackExchange.Redis
库中完全实现?
我发现有关于此主题的特定文档here。
现在我更加困惑因为*如果你执行整个spop
并且它不是MULTI
命令的一部分,并且当你在{{1}之后创建其他密钥时会发生什么,系统停机并使数据损坏?
所以...我错过了一些可以让我执行整个spop
并确保所有其他操作都要完成并保持下去的内容吗?
正如@BerinLoritsch在这里要求一些评论,我将使用Redis命令抛出一个伪代码来举例说明这里发生了什么:
spop
注意我不能使用MULTI
key1MemberValue = spop key1 1
sadd key2 key1MemberValue
zadd key3 1 key1MemberValue
EXEC
,因为我不知道我的真实案例中的集合成员。我需要随机弹出一个。
答案 0 :(得分:2)
最终,您需要了解redis multi / exec块与ADO.NET事务不同。从根本上说,以下(来自问题)在redis中是不可能的:
MULTI
key1MemberValue = spop key1 1
sadd key2 key1MemberValue
zadd key3 1 key1MemberValue
EXEC
因为您从spop
返回的内容是:QUEUED
。就这样。在EXEC
之前,您没有得到任何答案,因此无法在sadd
/ zadd
内使用此值MULTI
。
你可以在原始redis中可以想象的是WATCH
;但是,所有这些意味着如果WATCH
- ed键被另一个连接变异,则MULTI
/ EXEC
块被放弃,而不是执行;你仍然拥有spop
- ped。
所以从根本上说:是的,如果你希望在没有竞争连接使状态失效的情况下发生这种情况:你必须通过Lua和EVAL
/ EVALSHA
来完成 - 或者它需要更改{{ 1}} API。
答案 1 :(得分:0)
现在,实际上在我的特定情况下,还有另一种解决同一问题的方法,它允许我以原子性进行操作。
不使用spop
,而是使用Redis命令检查以下伪代码:
time = [current time]
member = zrangebyscore key1 -inf +inf limit 0 1
zrem key1 member
zadd key2 time member
zadd key3 time member
现在看来,最佳解决方案似乎是一个LUA脚本,它调用上面的代码列表的命令,因为Redis是单线程的,它可以一次发生一个操作,LUA脚本被认为是一个操作本身,如果我想确保其他操作不会尝试弹出相同的set
值,我觉得这应该是要走的路......
此外,我必须将常规集转换为排序集。由于Redis在复制和集群环境中避免数据损坏的限制,因此无法在非确定性命令之后调用写命令,无论是读操作还是写操作。感谢zrangebyscore
(它可能是zrange
,zrevrange
,zrevrangebyscore
...),因为它是确定性的,我可以模拟< em> pop 操作,仍然使用set语义。