Keys, Values and Channels
在 redis,keys 与其他有很大的区别。key 是数据库中数据的唯一标识(可以是 String,List,Hash 或任何其他 redis 数据类型)。此外,在处理集群或分片系统时,关键是定义包含此数据的节点(如果有副本,则为节点),因此,这些 key 对于路由命令至关重要。
与 values 形成对比。value 是针对 key 存储的东西:单独(针对 String 数据)或成组存储。value 不影响命令路由(注意:当指定 BY 或 GET 时,SORT 命令除外)。同样,出于操作目的,value 通常由 redis 解释:
- incr 命令把 string 当作 numeric
- 排序支持数字或 unicode 规则。
- 更多
关键是 API 需要了解什么是 key 和什么是 value。这反映在 StackExchange.Redis API 中,但好消息是,大多数时候你根本不需要了解这一点。
使用 pub/sub 时,我们正在处理 channels;channels 不影响路由(因此它们不是键),但是与常规 values 完全不同,因此应单独考虑。
Keys
StackExchange.Redis 通过 RedisKey
类型表示 keys。它可以与 string
或 byte[]
进行隐式转换,从而允许使用文本 key 和二进制 key 而不会造成任何复杂性。 例如,StringIncrement
方法将 RedisKey
作为第一个参数:
string key = ...
db.StringIncrement(key);
或者
byte[] key = ...
db.StringIncrement(key);
同样,有些操作会将 keys 作为 RedisKey
返回:
string someKey = db.KeyRandom();
Values
StackExchange.Redis 通过 RedisValue
类型表示 values。与 RedisKey
一样,存在隐式转换,例如:
db.StringSet("mykey", "myvalue");
但是,除了文本和二进制内容外,value 还可能需要表示类型化的原始数据:最常见的(以.NET术语)Int32
,Int64
,Double
或 Boolean
。 因此,与 RedisKey
相比,RedisValue
提供了更多的转换支持:
db.StringSet("mykey", 123); // this is still a RedisKey and RedisValue
...
int i = (int)db.StringGet("mykey");
请注意,虽然从 value 到 RedisValue
的转换是隐式的,但从 RedisValue
到 value 的许多转换都是显式的:这是因为如果数据没有适当的值,这些转换很可能会失败。
另外需要注意的是,在进行数字处理时,redis 将不存在的 key 视为零; 为了与此保持一致,将 nil 响应视为 0:
db.KeyDelete("abc");
int i = (int)db.StringGet("abc"); // this is ZERO
如果您需要检测nil条件,则可以进行检查:
db.KeyDelete("abc");
var value = db.StringGet("abc");
bool isNil = value.IsNull; // this is true
或更简单地说,只需使用提供的 Nullable<T>
支持:
db.KeyDelete("abc");
var value = (int?)db.StringGet("abc"); // behaves as you would expect
Hashes
由于 hashes 中的字段名称不会影响命令路由,因此它们不是 keys,而是可以同时使用文本名称和二进制名称。 因此,就 API 而言,它们被视为 values。
Channels
发布/订阅的 channel 名称由 RedisChannel
类型表示; 这在很大程度上与 RedisKey
相同,但是是独立处理的,因为尽管 channel name 是一级元素,但它们不会影响命令路由。
Scripting
Redis中的Lua脚本具有两个显着特征:
- 输入必须将 keys 和 values 分开(脚本内的键和值分别为 KEYS 和 ARGV)
- 返回格式没有预先定义:取决于你的脚本
因此,ScriptEvaluate
方法接受两个单独的输入数组:一个用于 keys 的 RedisKey[]
,一个用于 values 的 RedisValue[]
(两者都是可选的,并且如果省略则假定为空)。这可能是你实际上需要在代码中输入 RedisKey
或 RedisValue
的少数几次之一,这仅仅是由于数组差异规则所致:
var result = db.ScriptEvaluate(TransferScript,
new RedisKey[] { from, to }, new RedisValue[] { quantity });
(其中 TransferScript
是一些包含Lua的字符串,此示例未显示)
响应使用 RedisResult
类型(这是脚本编写所独有的;通常,API 会尝试尽可能直接和清晰地表示响应)。和以前一样,RedisResult
提供了一系列转换操作:实际上比 RedisValue
更多,因为除了被解释为文本,二进制,基元和可为空的基元之外,响应还可以解释为此类的数组,例如:
string[] items = db.ScriptEvaluate(...);
总结
在 API 中使用的类型经过精心选择,以区分 redis keys 和 values。在大多数情况下,提供自动转换操作。