3

我正在使用 Devart 的 DotConnect 产品将 .net 应用程序连接到 MySQL 数据库。一切运行良好,但在数据库中使用 SQL 时出现问题。

该应用程序使用 Guids 作为数据库中的行 id(最初来自 SQL Server 应用程序),它们在数据库中存储为 BINARY(16)(并在通过 .net 应用程序访问时使用 DevArt 的 MySQLGuid 类)

问题是,当我想查询数据库中的特定行时,我不能只粘贴数据库中 GUID 的字符串表示形式,所以我正在尝试制定一个函数来转换 GUID 的二进制表示形式到一个字符串。

起初,我认为在查询中调用 HEX(id) 是一件相当简单的事情,然后如果我想要一个友好的可读输出,我需要做的就是在适当的位置添加 -。

select 语句可能如下所示(实际上,我会将其包装为一个函数):

 LOWER(CONCAT(LEFT(HEX(theme_id), 8), '-', MID(HEX(theme_id), 9,4), '-', MID(HEX(theme_id), 13,4), '-', MID(HEX(theme_id), 17,4), '-', RIGHT(HEX(theme_id), 12)))

不会返回完全正确的 GUID。例如,如果我存储d1dfd973-fa3d-4b90-a1eb-47217162cd40然后上面的选择语句返回73d9dfd1-3dfa-904b-a1eb-47217162cd40

看起来前 8 个字节在组中的顺序颠倒了(取字符串 GUID 的第一部分,73d9dfd1从字节顺序的角度来看(即,将两个字符的组视为一个字节)是d1dfd973,这是正确的输出。

我的问题是——我可以在 MySQL 的 SQL 方言中执行一项操作,允许我反转相关部分的字节顺序吗?我可以做出更复杂的 LEFT/MID/RIGHT 语句,但这感觉不是一个好方法。

非常感谢您提出建议。

4

2 回答 2

1

例如,如果我存储d1dfd973-fa3d-4b90 -a1eb-47217162cd40 那么上面的选择语句返回73d9dfd1-3dfa-904b -a1eb-47217162cd40

我认为您的 GUID 遇到了小端/大端问题。有关 GUID,请参阅 wiki 页面上标题为“二进制编码”的部分:http ://en.wikipedia.org/wiki/Globally_unique_identifier

GUID 和 UUID 是 16 个字节的值,分为 4 个块:

Data1 : 4 byte int : big endian for UUID, little endian for ms/x86 GUIDs
Data2 : 2 byte int : big endian for UUID, little endian for ms/x86 GUIDs
Data3 : 2 byte int : big endian for UUID, little endian for ms/x86 GUIDs
Data4 : 16 bytes   : stored in the same order for both UUIDs and GUIDs

GUID 和 UUID 通常写为十六进制字符串,使用连字符分隔数据组件。这是踢球者,UUID 和 GUID 字符串都是用大端序的 Data 1-3 编写的。相同的字符串可以用不同的字节模式表示,具体取决于它们是存储在小端平台上的 UUID 还是 GUID 中。

让我们分解示例 GUID 的四字节 Data1 块:d1dfd973。如果此字符串表示 microsoft/intel 平台上的 GUID,则字节将按以下顺序出现在内存中:

guid[0] = 0x73 // LSB first
guid[1] = 0xd9
guid[2] = 0xdf
guid[3] = 0xd1 // MSB last

我认为这可能是Devart编写数据库的字节顺序。然后您的代码尝试使用

LEFT(HEX(theme_id), 8)

这将产生字符串 73d9dfd1 因为它只是按照存储顺序使用数据。

有一条线索表明我走在正确的轨道上:您的代码以正确的顺序读取 Data4(示例 GUID 中的 a1eb-47217162cd40)。无论平台以及我们谈论的是 UUID 还是 GUID,Data4 都以相同的字节顺序存储。

你有几个选择

  • 要求将所有内容作为小端 GUID 存储在数据库中。使用像 Andrzej 这样的转换例程来转换回字符串表示。

  • 要求存储的所有内容都是大端 UUID。运行一次转换以重新排序现有行的字节。您可以使用 Andrzej 的例程进行转换,但之后,您可以直接从二进制转换为字符串形式。

于 2015-01-08T19:47:34.670 回答
0

第1步)

我在 Mysql 中创建表

CREATE TABLE `table_code` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `code` varchar(45) DEFAULT NULL,
  `guid` binary(16) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;

第2步)

我插入一行:

INSERT INTO table_code (code,guid) 
VALUES ('d1dfd973fa3d4b90a1eb47217162cd40',UNHEX('d1dfd973fa3d4b90a1eb47217162cd40'));

步骤 3)

我跑

SELECT 
id,
code,
LOWER(CONCAT(LEFT(HEX(guid), 8),'-', MID(HEX(guid), 9,4), '-',MID(HEX(guid), 13,4), '-', MID(HEX(guid), 17,4), '-', RIGHT(HEX(guid), 12))),
LOWER(HEX(guid))

FROM test.table_code;

步骤 4) 结果是:

1   d1dfd973fa3d4b90a1eb47217162cd40    d1dfd973-fa3d-4b90-a1eb-47217162cd40 d1dfd973fa3d4b90a1eb47217162cd40

一切看起来都很好 - 在 Mysql 方面。

所以结论,你确定你正在插入 'd1dfd973fa3d4b90a1eb47217162cd40' (这应该通过使用 UNHEX('d1dfd973fa3d4b90a1eb47217162cd40') 来完成)或其他(反向)值。

无论如何,要把这样的字符串:“73d9dfd13dfa904ba1eb47217162cd40”变成这个“d1dfd973-fa3d-4b90-a1eb-47217162cd40”

您可以使用这样的代码:

LOWER(CONCAT(
MID(HEX(guid), 7,2),
MID(HEX(guid), 5,2),
MID(HEX(guid), 3,2),
LEFT(HEX(guid), 2),'-',
MID(HEX(guid), 11,2),
MID(HEX(guid), 9,2),'-',
MID(HEX(guid), 15,2),
MID(HEX(guid), 13,2),'-',
MID(HEX(guid), 17,4), '-', 
RIGHT(HEX(guid), 12)))

我认为 Mysql 并没有给我们更简单的方法,因为没有这样的函数对二进制数据进行操作。

要检查这一点:

步骤 5)

INSERT INTO table_code (code,guid) 
VALUES ('73d9dfd13dfa904ba1eb47217162cd40',UNHEX('73d9dfd13dfa904ba1eb47217162cd40'));

步骤 6)

    SELECT 
    id,
    code as `raw code`,
    LOWER(CONCAT(LEFT(HEX(guid), 8),'-', MID(HEX(guid), 9,4), '-',MID(HEX(guid), 13,4), '-', MID(HEX(guid), 17,4), '-', RIGHT(HEX(guid), 12))),
    LOWER(HEX(guid)) `decoded`,
LOWER(CONCAT(
MID(HEX(guid), 7,2),
MID(HEX(guid), 5,2),
MID(HEX(guid), 3,2),
LEFT(HEX(guid), 2),'-',
MID(HEX(guid), 11,2),
MID(HEX(guid), 9,2),'-',
MID(HEX(guid), 15,2),
MID(HEX(guid), 13,2),'-',
MID(HEX(guid), 17,4), '-', 
RIGHT(HEX(guid), 12))) as switched

    FROM test.table_code;

步骤 7) 似乎没问题。

于 2014-08-30T11:48:39.183 回答