1.11 键值通道

优质
小牛编辑
133浏览
2023-12-01

键、值以及通道

在对待Redis时候,键和其他的事物之间有个相当重要的区别。键是在数据库中一段数据的唯一标识(可能String,List,Hash或者其他的Redis数据类型)。键是没有任何实质意义,就是一个简单的名字。进一步说:当处理集群或者分片系统时,它就是定义在包含数据的节点上的Key,所以对于命令传送来说key是至关重要的。

值是相对于键来存储的。要么是单个(String数据)要么一组组的。值不会影响命令的传送(注意:除了SORT命令,并且该命令与BY或者GET组合使用的时候,但是这个真的很难解释说明;详细可以去看Redis的SORT命令文档)。值通常会被Redis以操作为目的来解读:

  • inc (各种类似的命令)解读字符串值作为数字数据

  • 排序:值要么以数值或以Unicode规则来排序

  • 还有很多其他的

关键点在于API需要明白什么是Key和什么是Value。这个涉及到StackExchange.Redis的API,但是大多数时候你根本不需要知道这个。

当你在使用发布/订阅时,我们是使用通道来处理的;通道不影响到命令传送(所以它们不是Keys),但是这与常规值是区别巨大的,所以应该分别考虑。

Keys

StackExchange.Redis中键的类型是 RedisKey。不过好在它会隐式的从 stringbyte[] 转换,允许使用文本和二进制键。例如:StringIncrement 方法将 RedisKey 作为第一个参数,但是你不需要自己去做转换,例如:

string key = ...
db.StringIncrement(key);

或者

byte[] key = ...
db.StringIncrement(key);

同样的,有一些方法能够返回 RedisKey 类型的key;如下所示:

string someKey = db.KeyRandom();

Values

StackExchange.Redis中的值的类型是 RedisValue。与 RedisKey 一样,它也可以隐式转换;这意味着你大多数时候都看不到该类型,例如:

db.StringSet("mykey", "myvalue");

然而,除了文本和二进制内容外,值还可以被表示为其他原生类型,如:Int32, Int64, Double, Boolean。正因为如此,RedisValue 提供了大量的隐式转换支持,而 RedisKey 则没有这么多:

db.StringSet("mykey", 123); // 这仍旧是一个RedisKey 和 RedisValue
...
int i = (int)db.StringGet("mykey");

注意:从原生类型到 RedisValue 的转换都是隐式的,但是从 RedisValue 转换为原生类型是显示转换:如果数据没有一个适当的值,这些转换很有可能会失败。

注意:当值是数值类型时,Redis去获取一个不存在(no-existent)的键值时,该值会以数值0返回;为了一致性,nil响应被视作为0:

db.KeyDelete("abc");
int i = (int)db.StringGet("abc"); // 这个会被作为0返回

如果你需要检测nil条件,那么你可以这样做:

db.KeyDelete("abc");
var value = db.StringGet("abc");
bool isNil = value.IsNull; // 这个表示真

或者这样做更简单,使用 Nullable\

db.KeyDelete("abc");
var value = (int?)db.StringGet("abc"); // 正如你所期望的,会返回空

Hashes

由于哈希表中的字段名不会影响到命令的传送,他们也不是key,但是文本和二进制可以作为名字使用;因此它们被视作为值。

Channels

发布/订阅所使用的管道名字的类型是 RedisChannel;大致上来说和 RedisKey 相同,但是被独立处理的,因为管道名称是头等公民,它们不会影响命令的传输。

Scripting

Redis中的Lua脚本有两个值得注意的特性:

  • 输入必须保证键值分离(在脚本内会分别变成 KEYSARGV)

  • 返回的格式没有被预先定义:这取决于你的脚本

由于这个原因,ScriptEvaluate 方法接受两个单独的输入数组:一个是作为Key的 RedisKey[],一个是作为Value的 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的Key和Value。然而,几乎在所有情况下,你不需要直接引用所涉及的基础类型,默认提供了转换操作。