书架是否支持CAS操作(即Redis WATCH命令)?例如,如何实现类似下面的内容?
WATCH mykey
val = GET mykey
val = val + 1
MULTI
SET mykey $val
EXEC
当多个线程尝试使用相同的数据修改同一个对象时,我需要这样做以避免竞争条件。
答案 0 :(得分:2)
目前在nuget,我不这么认为。因为BookSleeve 通常打算用作多路复用器,这使得“监视”无法使用。我可以添加它,你必须在操作期间限制使用到一个调用者(每个BookSleeve连接)。
这has now changed;如果我们想手动实现INCR
(根据您的示例),我们可以使用:
// note this could be null if the old key didn't exist
var oldVal = await connection.Strings.GetInt64(db, key);
var newVal = (oldVal ?? 0) + 1;
using (var tran = connection.CreateTransaction())
{
// check hasn't changed (this handles the WATCH, a checked GET,
// and an UNWATCH if necessary); note tat conditions are not sent
// until the Execute is called
tran.AddCondition(Condition.KeyEquals(db, key, oldVal));
// apply changes to perform assuming the conditions succeed
tran.Strings.Set(db, key, newVal); // the SET
// note that Execute includes the MULTI/EXEC, assuming the conditions pass
if (!await tran.Execute()) return null; // aborted; either a pre-condition
// failed, or a WATCH-key was changed
return newVal; // successfully incremented
}
显然你可能希望在重复(在理智的限制内)循环中执行它,这样如果它因WATCH
而中止,你就从头开始重做。
这与您的示例略有不同,因为它实际上是这样(假设在初始GET
和第二个GET
之间没有更改值):
val = GET mykey
newval = (val ?? 0) + 1
WATCH mykey
chk = GET mykey // and verifies chk == val as part of the Execute
MULTI
SET mykey $newval
EXEC
如果EXEC
和WATCH
之间的值已更改,则EXEC
仍然可以报告取消;或者(如果 在两个GET
之间发生了):
val = GET mykey
newval = (val ?? 0) + 1
WATCH mykey
chk = GET mykey // and verifies chk == val as part of the Execute
UNWATCH
差异是另一个GET
,但这是它可以与多路复用器一起使用的唯一方式 - 即,Execute
被优化为可靠快速,因此它不会影响其他来电者。