本文描述了表示 GUID 的新数据类型的实现。其中包括一个用户定义的例程(User-Define Routine,UDR),该例程在操作系统的帮助下生成 GUID 。
Informix® Dynamic Server 9.x(IDS 9.x)支持用多种方法来创建惟一标识符。最初的方法是使用带有惟一性约束的 SERIAL
类型。IDS 9.x 添加了 SERIAL8
类型,这个 8 字节的整型值实际上提供了无数多个标识符。通过使用惟一性约束,SERIAL8 实际上可以提供无数多个惟一标识符。 SERIAL
和 SERIAL8
都特定于一个给定的表。
从 IDS 9.4 开始,我们还可以使用 SEQUENCE
对象来生成可用于数据库中任何表的标识符。只要通过一个特定的序列来完成,实际上就确保了生成用于数据库中任何表的惟一标识符。
随着分布式系统和公司间协同的不断普及,就需要生成并操作确保在世界范围都是惟一的标识符。这可以借助操作系统生成全局惟一标识符(Globally Unique Identifier,GUID)以及使用可操作 GUID 的 opaque 类型来完成。
这篇文章描述了表示 GUID 的新数据类型的实现。其中包括一个用户定义的例程(User-Define Routine,UDR),用于借助操作系统来生成 GUID。
这类标识符也称作 UUID:Universally Unique Identifier。它是由一系列的十六进制数来表示的,例如:
2ac07282-184e-4103-ad2a-ad8abdab8f0b
这是一个 36 个字符的串。而在内部将表示为 16 字节的二进制串。如果要使用其字符表示,那么所需的空间则会比它的两倍还要多。我们需要一种新的数据类型,用以既容纳内部表示又容纳外部表示。
IDS 9.4 允许您创建自己的类型。其中称作 opaque 的类型就允许您定义其内部结构:
CREATE OPAQUE TYPE Guid
(INTERNALLENGTH=16, alignMENT=4);
本例中是一个固定长度的 opaque 类型。而 IDS 9.x 还支持变长的 opaque 类型。由于它是不透明的(opaque),所以您必须向数据库服务器提供附加函数以允许它来操作该类型。
所需的函数如下:
- Input/Output:实现外部(字符)表示和内部(二进制)表示的相互转换。
- Import/Export:与 Input/Output 函数相似,但只用于成批的加载和卸载。
- Send/Receive:在客户机和服务器之间提供二进制转换。这对于服务器和客户机之间字节次序的转换是必需的。
- ImportBinary/ExportBinary:类似处理二进制数据的 Import/Export。
- 比较(Comparison)函数:用于 WHERE 子句中的比较和索引。
为了达到本文中的目的,我们需要实现 Input/Output、Send/Receive 和比较函数。前四个函数将通过强制转换定义映射到 opaque 类型上。因为它们也提供了 Import/Export 和 ImportBinary/ExportBinary 函数的功能,所以我们可以使用它们的实现并且创建接收合适类型参数的附加强制转换。强制转换的语句如下:
CREATE IMPLICIT CAST (lvarchar AS GUID WITH guid_in);
CREATE CAST (guid AS lvarchar WITH guid_out);
CREATE IMPLICIT CAST (impexp AS GUID WITH guid_imp);
CREATE CAST (guid AS impexp WITH guid_exp);
CREATE CAST (guid AS sendrecv WITH guid_send);
CREATE IMPLICIT CAST (sendrecv AS guid WITH guid_recv);
CREATE CAST (guid AS impexpbin WITH guid_expbin);
CREATE IMPLICIT CAST (impexpbin AS guid
WITH guid_impbin);
前面两条语句提供了外部表示(字符)和内部表示(二进制)之间的转换。接着的两条语句为字符表示的成批加载和卸载提供了转换功能,例如在 dbacesss 函数加载和卸载的情况下。接下来的两个强制转换说明如何在客户机和数据库服务器之间对二进制表示进行转换。最后两条则提供了对于二进制格式的成批加载和卸载的映射。
关于 opaque 类型的更多信息,请查阅本文最后参考资料小节中所列的手册。
除了支持新的 GUID
类型,IDS 9.x 还可以用于生成全局惟一标识符。我们可以创建名为 makeguid()
的函数。该函数可通过几种方式来使用:
EXECUTE FUNCTION makeguid();
INSERT INTO tab(guidcol) VALUES(makeguid());
第一种方法允许您检索新的 GUID
并使用它。第二种方法生成一个 GUID
并且将之插入包含 GUID
类型列的表中。
一旦注册到数据库, GUID
类型就成为了一种被完全支持的类型,就像 DECIMAL
或 INTEGER
等其他类型一样。它可以用作主键或索引的一部分。您可以通过其内部格式或字符表示将值插入该列,也可以在 WHERE 子句中使用它:
CREATE TABLE tab( col1 guid);
INSERT INTO tab VALUES("2ac07282-184e-4103-ad2a-ad8abdab8f0b");
SELECT col1 FROM tab WHERE col1 > "0ac07282-184e-4103-ad2a-ad8abdab8f0b";
在最后一个示例中,我们看到其中将 GUID 类型的列 coll 与 GUID 的字符表示进行比较。这种比较是允许的,因为其实现中已定义了字符串和 GUID 之间隐式的强制转换。在进行比较之前,字符串将被转换为 GUID 的内部表示。
大多数编程接口提供了两种方式来检索 SQL 语句的结果。它既以字符格式又以二进制格式进行检索。如果不希望必须要操作内部表示(二进制),您可以将该列值显式地转换为其字符格式。例如:
SELECT col1::lvarchar FROM tab;
该表达式将 coll 强制转换为 lvarchar
,这是变长字符串的一种形式。实际上就是将内部表示转换为 36 字节字符串的外部表示。
要从 Java 程序中操作这个新的数据类型,您首先必须创建一个表示它的 Java 类。这个新的类必须实现 SQLData 接口。该接口定义了三个方法:
getSQLTypeName
:该方法返回 SQL 类型的名称。
readSQL
:该方法接收数据流(SQLInput)并且用其初始化该对象的内容。
writeSQL
:该方法接收输出流(SQLOutput)并且将该对象的内容写入其中。
对于了 Guid
类型, readSQL
和 writeSQL
方法十分简单,因为它们仅需要从/向该流读取/写入 16 个字节。
在使用新类之前,您必须在类型映射中注册它。以下是注册 Guid
类来操作该 opaque 类型的代码段:
java.util.Map map = conn.getTypeMap();
map.put("Guid", Class.forName("Guid"));
conn.setTypeMap(map);
当 Guid 对象与 SQL 语句关联时,基本上您只需要对 Guid 对象执行两种操作:将 Guid 作为参数传递以及从 ResultSet 接收 Guid。
要将 Guid 作为参数传递给 SQL 语句,您可使用 PrepareStatement 对象的 setObject 方法:
pstmt = conn.prepareStatement(sqlstmt);
Guid myGuid =
new Guid("0ac07282-184e-4103-ad2a-ad8abdab8f0b");
pstmt.setObject(1, myGuid);
您也可以使用 setString()
方法将参数作为字符串来传递。用 getObject()
方法从 ResultSet 中检索 Guid 列:
Guid col1Guid = (Guid)rs.getObject(1);
然后,您便可以将结果当作 Guid
对象来操作并且按照标准的 Java 处理进行。
对于 Java 程序,当打开游标时,您可以将 Guid
的值作为字符串传递给准备好的语句。而对于接收二进制格式的 Guid
,您可以声明一个结构并将之用于固定的二进制声明中:
typedef struct Guid {
unsigned char values[16];
} GUID;
EXEC SQL BEGIN DECLARE SECTION;
fixed binary 'guid' GUID id;
EXEC SQL END DECLARE SECTION;
有了这些声明,您就可以读取 id 变量并且按照其声明(16 位无符号字符数组)来使用它。
本文附带了示例实现,其中实现了上述的所有函数。它还包括了 Java 和 ESQL/C 的客户机实现。
关于如何编译和使用的细节问题,请查阅 README 文件。
该示例实现已经在 Linux 和 Windows 2000 上进行了测试。Windows 2000 版本无法实现 makeguid()
函数,因此其执行返回的是一个错误“ makeguid() Not implemented
”。 makeguid()
函数依赖于操作系统平台所提供的 uuid_generate()
函数调用。而 Linux 的这个函数遵循针对全局惟一标识符的 OSF DCE 1.1 规范。
如果需要在任何 Unix 平台上使用该实现,您只需要确保 uuid_generate()
函数或其等效函数在您所选择的平台上是可用的。否则,您只是无法使用 makeguid()
函数,但仍然可使用 Guid 类型。
如果您使用的是 AIX,就请查看 dce/uuid.h
下和函数 uuid_create()
处的 uuid_t
的定义。
当输入串不遵循合适的格式,或者您调用未实现的 makeguid()
时,该实现则可能产生异常。这些错误直接来自于代码中。您可以在系统目录中创建自己的异常,这将允许您国际化这些异常。
guid_in()
输入函数假定所进入的字符是 ASCII 格式的。如果您的环境不同,则还需要将之重写。
IDS 9.x 提供了将新数据类型集成到数据库中的能力。这给您带来了极大的灵活性,可更好地将数据库服务器和商业解决方案的设计更好地集成。而 GUID 类型便是该功能的一个例子,它被看作是数据库中的第一个类(class)类型的对象。
数据库中新类型的集成允许您利用关系模型的长处,例如搜索、排序以及分组,而无需在客户机代码中复制这些功能。该方法可以简化您的解决方案并且产生商业优势以超过竞争对手。
- Informix Dynamic Server.2000: Server-Side Programming in C,Informix Press,ISBN 0-13-013709-X,Jacques Roy
- IBM Informix DataBlade API Programmer's Guide,Version 9.4,(G251-1258-00)
- IBM Informix DataBlade API Function Reference,Version 9.4,(G251-1257-00)
描述 |
文件类型 |
文件大小 |
下载方法 |
uuid.zip |
zip |
18KB |
HTTP |
|
|
|
Jacques Roy 是 IBM 全球销售支持组织的成员。他拥有超过 20 年的行业经验以及超过 5 年的数据库可扩展性方面的经验。他是 Informix Dynamic Server 2000: Server-Side Programming in C 的作者以及 Open-Source Components |