管道和事务
了解如何使用 Redis 管道和事务
Redis 允许您将一系列命令一起批量发送到服务器。您可以使用两种类型的批处理:
- 管道通过在一次通信中将多个命令一起发送到服务器来避免网络和处理开销。然后服务器通过一次通信返回所有响应。更多信息请参阅管道页面。
- 事务保证所有包含的命令将执行完成,而不会被其他客户端的命令中断。更多信息请参阅事务页面。
执行管道
要通过管道执行命令,您首先创建管道对象,然后使用类似于标准命令方法的异步版本(例如,StringSetAsync()
和 StringGetAsync()
)向其添加命令。命令在管道中缓冲,只有当您调用管道对象的 Execute()
方法时才会执行。
var pipeline = new Pipeline(db);
for (int i = 0; i < 5; i++) {
pipeline.Db.StringSetAsync($"seat:{i}", $"#{i}");
}
pipeline.Execute();
var resp1 = db.StringGet("seat:0");
Console.WriteLine(resp1); // >>> #0
var resp2 = db.StringGet("seat:3");
Console.WriteLine(resp2); // >>> #3
var resp3 = db.StringGet("seat:4");
Console.WriteLine(resp2); // >>> #4
执行事务
事务的工作方式与管道类似。创建 Transaction
类实例,在该对象上调用异步命令方法,然后调用事务对象的 Execute()
方法来执行它。
var trans = new Transaction(db);
trans.Db.StringIncrementAsync("counter:1", 1);
trans.Db.StringIncrementAsync("counter:2", 2);
trans.Db.StringIncrementAsync("counter:3", 3);
trans.Execute();
var resp4 = db.StringGet("counter:1");
Console.WriteLine(resp4); // >>> 1
var resp5 = db.StringGet("counter:2");
Console.WriteLine(resp5); // >>> 2
var resp6 = db.StringGet("counter:3");
Console.WriteLine(resp6); // >>> 3
监视键的更改
Redis 支持乐观锁以避免对不同键进行不一致的更新。基本思想是,在您处理更新时,监视事务中使用的任何键的更改。如果被监视的键确实发生更改,则必须使用键中的最新数据重新开始更新。有关乐观锁的更多信息,请参阅事务。
其他客户端使用的乐观锁方法(将 WATCH
命令显式添加到事务中)与 NRedisStack
使用的多路复用系统配合不佳。相反,NRedisStack
依赖于命令的条件执行来实现类似效果。
使用 AddCondition()
方法可以在事务执行期间特定条件不成立时中止事务。如果事务中止,则 Execute()
方法返回 false
值,否则返回 true
。
例如,如果指定键存在或在事务执行期间被其他客户端添加,则 KeyNotExists
条件会中止事务。
var watchedTrans = new Transaction(db);
watchedTrans.AddCondition(Condition.KeyNotExists("customer:39182"));
watchedTrans.Db.HashSetAsync(
"customer:39182",
new HashEntry[]{
new HashEntry("name", "David"),
new HashEntry("age", "27")
}
);
bool succeeded = watchedTrans.Execute();
Console.WriteLine(succeeded); // >>> true
您还可以对某些单独命令使用 When
条件,以指定它们仅在满足特定条件时执行(例如,该命令不更改现有键)。有关事务和命令条件的完整说明,请参阅条件执行。