MongoDB 中 GUID 数据的 3 个最佳实践





0/5 (0投票)
仔细研究一下在 MongoDB 环境中处理 GUID 和 UUID 时会遇到的棘手情况。我们将让您了解这些配置,并提供一套最佳实践供您遵循。
引言
GUID 通常用于标识软件创建的自定义对象。软件开发人员经常在数据库中显式存储这些标识符,而不依赖于数据库系统生成的标识符。
MongoDB 和 MongoDB 驱动程序内置了对 GUID/UUID 数据类型的支持。无需查阅 DB 规范,即可轻松便捷地开始使用 GUID/UUID。在大多数情况下,您应该都不会有问题。但有些情况下,您可能会遇到一些难以调试的意外问题。
一旦您的部署涉及到多种语言,您可能会发现您的应用程序不再按预期工作,例如,您可能无法再将订单与客户匹配。随着时间的推移,您的数据也很可能损坏,如果不恢复备份(您会定期备份,对吧?),将很难从这种灾难中恢复。
在本文中,我们将仔细研究 GUID/UUID 可能变得更加复杂的场景。我们将让您了解这些配置,并为您提供一套最佳实践供您遵循。
什么是 UUID?什么是 GUID?
通用唯一标识符(UUID)是计算机软件中用作标识符的唯一编号。有时也使用全局唯一标识符(GUID)来描述它。GUID 是 UUID 标准的众多实现之一。
UUID 是 128 位值,通常显示为 32 个十六进制数字,用连字符分隔,例如
176BF052-4ECB-4E1D-B48F-F3523F7F277F
(上面的示例是随机的 V4 版本 UUID)
MongoDB 和 GUID/UUID 支持
MongoDB 内置了对 GUID/UUID 数据类型的支持,并且大多数 MongoDB 驱动程序都原生支持 GUID/UUID。MongoDB 本身将它们存储为 Binary(二进制)字段,当软件访问这些 Binary 字段时,MongoDB 驱动程序通常会将数据库中的值转换为特定语言的 GUID 或 UUID 对象。例如,当您使用 C# 驱动程序从 MongoDB 数据库读取 UUID 时,将返回 System.GUID
类型的对象。而 Java 驱动程序将返回 java.util.UUID
类型的对象。
这使得从应用程序代码中处理 GUID/UUID 数据类型非常方便和容易。
是的,有陷阱
然而,在多平台/多语言环境中使用 UUID 时,您可能会遇到问题,因为使用不同的 MongoDB 驱动程序从不同编程语言访问数据库可能并不总是安全,如下所示。此外,您在使用第三方 MongoDB 管理软件处理 UUID 数据类型时应谨慎,因为只有少数 MongoDB 工具能妥善处理 UUID 数据类型。 MongoChef 是一个支持此功能的 MongoDB GUI 示例,它提供了不同的选项来确保 UUID 被正确解释、写入和更新。
MongoDB 驱动程序通常会在 Binary 数据库表示和特定语言的 UUID 数据类型之间转换 UUID。最初,编码方法是平台特定的,并且在不同的 MongoDB 驱动程序之间没有一致实现。
示例
在 C# 应用程序中创建和显示的示例 GUID 将如下所示:
00010203-0405-0607-0809-0A0B0C0D0E0F
MongoDB C# 驱动程序(默认配置)会将其转换为 Binary 数据库表示,并以以下字节顺序存储:
03 02 01 00 05 04 07 06 08 09 0A 0B 0C 0D 0E 0F
然而,用于访问同一字段的 Java 驱动程序将返回并显示以下内容:
06070405-0001-0203-0F0E-0D0C0B0A0908
Python 驱动程序将再次显示不同的内容:
03020100-0504-0706-0809-0A0B0C0D0E0F
您会注意到,同一 UUID 的表示形式因访问它的平台而异!
只要您不在两端编辑这些 UUID,您就不应该遇到任何严重问题(除了分析数据时感到困惑)。然而,如果有一天您确实编辑了 UUID,您很可能会遇到难以查找和调试的问题,因为您实际上是在处理混乱的数据。
Binary 子类型 0x03 和 0x04
在查看 BSON 规范时,您会注意到分配给 UUID 数据类型的两个 Binary 子类型:
最初,只有 0x03 子类型用于表示 UUID。为了解决多平台环境中因特定语言的 UUID 实现而出现的便携性问题,MongoDB 设计者后来引入了新的 0x04 子类型。
使用 0x04 子类型的 Binary 字段存储 UUID 的字节顺序现在在所有 MongoDB 驱动程序中得到了一致的实现,并且仅为旧数据支持旧的 0x03 子类型。
使用 Binary 子类型 0x04 处理 UUID 可确保您能够从任何平台和任何编程语言访问数据,而不会出现兼容性问题。
最佳实践
1. 确保您始终知道您的应用程序正在使用哪种 UUID 子类型
您可以通过查看现有数据的 JSON 表示(例如在 mongo shell 中)来找出正在使用的子类型:
示例
BinData(3,"B0AFBAMCAQAPDg0MCwoJgA==")
表示以旧的 0x03 子类型存储为 Binary 字段的 UUID
BinData(4,"SDcTgfx0SOq0Cl7DMRAzDQ==")
表示以 0x04 子类型存储为 Binary 字段的 UUID
您也可以使用支持旧版 UUID 的 MongoDB GUI 来访问此信息。MongoChef 将常规 UUID 注释为Binary - UUID,对于旧版 UUID,它会告知您当前使用的编码(例如 Java、C# 或无编码)。
2. 为新部署配置您的驱动程序以使用子类型 0x04
MongoDB 驱动程序通常默认将 UUID 存储为分配了旧 0x03 子类型的 Binary 字段。此配置可以更改。
C#
您可以通过修改 BsonDefaults.GuidRepresentation 的值来覆盖驱动程序的默认设置,并配置它使用 Binary 0x04 子类型。
BsonDefaults.GuidRepresentation = GuidRepresentation.Standard;
您也可以在服务器、数据库和集合级别修改 GuidRepresentation
。
Python
您可以配置 Python 驱动程序的行为。在此处阅读有关 uuid_subtype 属性的更多信息:here。
Java
UUID 配置支持将在 MongoDB 驱动程序的 3.0 版本中添加。对于当前(3.0 之前)的驱动程序,您将需要自己执行转换。
/**
* Convert a UUID object to a Binary with a subtype 0x04
*/
public static Binary toStandardBinaryUUID(java.util.UUID uuid) {
long msb = uuid.getMostSignificantBits();
long lsb = uuid.getLeastSignificantBits();
byte[] uuidBytes = new byte[16];
for (int i = 15; i >= 8; i--) {
uuidBytes[i] = (byte) (lsb & 0xFFL);
lsb >>= 8;
}
for (int i = 7; i >= 0; i--) {
uuidBytes[i] = (byte) (msb & 0xFFL);
msb >>= 8;
}
return new Binary((byte) 0x04, uuidBytes);
}
/**
* Convert a Binary with a subtype 0x04 to a UUID object
* Please note: the subtype is not being checked.
*/
public static UUID fromStandardBinaryUUID(Binary binary) {
long msb = 0;
long lsb = 0;
byte[] uuidBytes = binary.getData();
for (int i = 8; i < 16; i++) {
lsb <<= 8;
lsb |= uuidBytes[i] & 0xFFL;
}
for (int i = 0; i < 8; i++) {
msb <<= 8;
msb |= uuidBytes[i] & 0xFFL;
}
return new UUID(msb, lsb);
}
3. 配置您的 MongoDB GUI 以处理旧版 UUID 和子类型 0x03
只有少数 MongoDB GUI 工具允许您指定如何处理旧版 UUID 字段。
MongoChef 内置了对 0x03 和 0x04 子类型的支持。您可以在 Properties(属性)对话框中配置行为,并从以下选项中进行选择:
- 旧版 .NET / C# 编码
- .NET/C# 驱动程序使用的默认编码:像 .NET 应用程序那样读取、存储和显示 UUID
- 旧版 Java 编码
- Java 驱动程序使用的默认编码:像 Java 应用程序那样读取、存储和显示 UUID
- 旧版 Python 编码
- Python 驱动程序使用的默认编码:像 Python 应用程序那样读取、存储和显示 UUID
- 无编码 / 原始数据
- 不执行任何转换,数据以现有字节顺序读取、存储和显示
摘要
确保您的应用程序在处理 UUID 数据类型时不会受到不必要的便携性问题的影响,并尽可能避免使用旧版 Binary 0x03 子类型。如果您无法将现有部署迁移到新的 Binary 0x04 子类型,请记住将您的 MongoDB 工具配置为正确的旧版 Binary 0x03 子类型编码。
关于作者
Tomasz 是一名软件开发人员,也是 3T Software Labs 的联合创始人,他和他的团队在那里构建 MongoDB 开发人员工具:3T MongoChef、3T Data Compare & Sync 和 3T Schema Explorer & Documentation。您可以在 http://3t.io/mongochef/ 找到有关 3T 及其 MongoDB GUI 工具的更多信息。