级别: 中级 Kathy Zeidenstein, 数据管理 信息集成策略和标准, IBM 硅谷实验室
2002 年 6 月 01 日 描述 DB2 版本 7 对用户定义的结构化类型和诸如继承、方法、对象标识符、通过引用的导航和方法的动态调度(多态性)等其它功能的支持。为了提高性能,索引扩展允许在结构和区别类型数据上创建用户定义的索引规范。对 JDBC 2.0 和 SQLJ Part 2 的支持提供了编程环境和数据库服务器之间更紧密的集成。
本文的
第 1 部分介绍了 DB2 中的对象-关系(object-relational)功能,并给出了如何创建结构化类型(structured type)和如何用这些类型创建用于存储结构化类型对象的表的示例。在第二部分,我将描述如何在列定义中使用结构化类型。我还将描述如何在对象(存储在类型表或列中)中调用方法,如何用变换函数来使应用程序能够操作这些对象,还有 SQLJ 和 JDBC 扩展,这些扩展对于将这些数据库对象集成到 Java 应用程序中将是有帮助的。
在列中存储对象
实体属性本身可能就很适合选择用结构化类型来表示。即使一些简单如地址的东西也可以选择用结构化类型来表示。地址有 — 街道门牌号、街道名称、城市、州和邮政编码 — 等可以表示为属性的结构。而且它是可重用的。在定义了这个类型及其方法之后,就可以在需要用到地址的许多场合中使用它:
创建地址类型及其方法。
CREATE TYPE Address_t AS
(Number VARCHAR (10),
Street VARCHAR(30),
City VRACHAR(20),
Zip VARCHAR (15)
...)
METHOD distance (address_t)
RETURNS FLOAT
LANGUAGE C
...
METHOD addrstring ()
RETURNS CHAR(70)
LANGUAGE C
...
|
创建方法体。(请注意为这些外部方法使用了变换分组(transform group)规范。欲了解关于变换的更多信息,请参阅
为应用程序变换对象)
CREATE METHOD distance(address_t)
FOR Address_t
EXTERNAL NAME 'addrlib!distanceaddr'
trANSFORM GROUP func_group...
CREATE METHOD addrstring()
FOR address_t
external name 'addrlib!formataddress'
trANSFORM GROUP func_group
..
|
使用列规范中的结构化类型来创建表。
CREATE table properties
(ID integer,
Address Address_t,
Picture BLOB)
...
|
插入和更新列对象
每当创建了用户定义的结构化类型时,DB2 都自动创建有助于您构造对象、观察(检索)或更改(更新)其属性的例程。这些例程对应于 OO 编程语言中的 gettor 和 settor。
- 如果类型是 Address_t,则构造函数就是 Address_t()。这个函数返回类型 Address_t 的一个实例,其所有属性都被设置为 null。
- 对应每个属性都有一个观察器方法。例如,街道属性的观察器方法是 Address_t .. street() ,它返回一个 VARCHAR(30) 街道名称。
- 对应每个属性都有一个更改器方法。例如,街道属性的更改器方法是 Address_t .. street (VARCHAR(30)) ,它返回地址,其中的街道属性被更新为在该方法的输入参数中指定的值。
Address_t 的任何子类型都继承上述例程,但对于任何它所拥有的额外属性,它也有自己的观察器和更改器。
这些方法,是 DB2 中的列对象的所有方法,用双点语法(
type_instance..
method)进行调用。例如,要插入一个新地址,请使用构造函数(用黑体显示)构造一个空实例,然后,使用更改器方法将属性设置为新的值:
INSERT INTO Properties (ID, Address)
VALUES (1224, Address()..street('555 Bailey Avenue')
..city('San Jose')
..state('CA')
..zip('95141');
|
要更新现有的值,可以象下面这样使用更改器:
UPDATE Properties
SET Address = Address..street('Barley Avenue')..zip('95000')
WHERE Address..street LIKE 'Bailey Avenue';
|
UPDATE Properties
SET Address..street='Barley Avenue',
Address..zip ='95000'
WHERE Address..street LIKE 'Bailey Avenue';
|
或者,完成同样一件事的一种更容易的方式是:
这个示例显示了 zip 属性的观察器方法在 WHERE 子句中的使用:
SELECT ID, Picture
INTO :id, :picture
FROM properties
WHERE Address..zip LIKE '95%'
|
同样的调用可在用户定义的方法中使用。这个示例在地址的一个实例中调用 distance 方法:
SELECT ID
INTO :id,
FROM properties P, stores S
WHERE P.Address..distance(S.Address)< 1
|
这个示例在 SELECT 列表中调用 addrstring 方法:
SELECT ID, Address..addrstring()
FROM Properties
WHERE Address..zip LIKE '95141';
|
索引列对象
用户定义的索引扩展用来在结构化类型列中创建索引。一般的 B-树索引不足以完成对复杂域的高效搜索,因为这些索引依赖于所有数据值的“总排序”,这种“总排序”使得诸如“查找所有大于 25000 的薪资”这样的搜索易于完成。不存在对结构化类型的自动比较,这就是转而根据行为创建索引的原因。例如,您可以创建一个能理解距离的索引,这就是使“高效地查找在另一个地址的一定距离内的点”成为可能的办法。换句话说,索引扩展就是将您的数据的语义信息转移到 DB2,以使 DB2 能够用这些信息生成更高效的查询的方式。作为一个示例,DB2 的 Spatial Extender 使用索引扩展将坐标信息转换成 DB2 能够识别的形式。
在存储在行中的对象中调用方法
可在存储在行中的对象(例如存储在 Person_table 层次结构中的对象)中调用方法。本文中关于行对象的所有示例都着力于将类型表的一行看作具有不同值的独立的列。
不过,若要调用某个雇员的方法,则必须将该行对象转换成带有封装属性的对象。
DEREF 函数是将行转换成对象的方法。DEREF 操作在 REF 类型列(本表或所引用的表的对象标识符),它抓取所引用的行并将它转换成一个对象。通过对类型表的对象标识符调用 DEREF,所返回的行被转换成带有封装属性的结构化类型对象。
您可以对一个对象进行的操作之一是将它插入到同类型的列中。SQL 语句立即将来自 Person_table 层次结构的行转换成对象,以便能够将它插入到另一个表中 Person 类型的结构化类型列。
要调用对象的方法,也必须使用 DEREF。在展示方法调用的示例之前,让我们首先添加一个简单的用 SQL 编写的方法,用来计算执行官的总报酬。因为这是一项简单的操作,所以我们可以只是用 SQL 编写一个将从薪资和红利中观察到的属性加起来的方法。
altER TYPE executive ADD METHOD
total_comp ()
RETURNS integer
LANGUAGE SQL
...
CREATE METHOD total_comp ()
RETURNS INTEGER
FOR executive
RETURN
SELF..Salary + SELF..Bonus
|
可通过 altER TYPE 语句将方法添加到类型中。
这里是 CREATE METHOD 语句。对于用 SQL 编写的方法,其方法体在 RETURN 子句中指定。SELF 指方法的第一个隐式参数,这个参数总是该方法所被指定的类型,在这个例子中,是 executive。SELF 对应于 C++ 和 Java 中的“this”。
调用 total_comp 方法的一种方式是使用 DEREF 函数,如上所示:
SELECT Name, DEREF(oid)..total_comp AS total_comp FROM exec_table;
|
不过,反引用一个对象并调用这个方法有一种更简单的方式,即使用反引用操作符(->)。如果箭头右边的名称不是目标类型的一个属性,则它被看作一个方法调用:
SELECT Name, oid->total_comp AS total_comp FROM exec_table;
|
下面的示例显示 WHERE 子句中的方法调用:
SELECT E. name, E. salary, E.dept->ID, E.dept->table;
FROM Employee_table E
WHERE E.dept->budgetPerPerson( ) > 150000;
|
额外的查询增强功能
以下增强功能是找出关于对象类型的信息和控制按类型进行的查询搜索的有用工具。
返回类型信息的内置函数:以下示例所显示的内置函数返回对象的动态类型名、类型模式或内部类型标识符:
SELECT name, TYPE_NAME(DEREF(oid)) AS typename,
TYPE_SCHEMA(DEREF(oid)) AS type_schema, <
TYPE_ID (DEREF(oid)) AS type_id
FROM Person_table;
|
类型谓词
:在
第一部分中,在 FROM 子句中使用 ONLY 是为了将查询结果限制为仅仅是所指定的表;在结果中不包含子表行。类型谓词是 ONLY 的更一般的形式。为了使用它,查询所返回的每个对象的动态类型都与您在类型谓词中已经指定的类型的列表相比较。对象的动态类型就是该对象最初被插入到的表的类型。仅当所返回的对象的类型在列表中时谓词为真。例如,以下的查询仅返回那些出生于 1960 年之后
并且正好是 Person 类型,或者是 Student 类型,或者 Student 的任何子类型的人员。
|
SELECT *
FROM Person_table
WHERE birthyear
<1960 AND DEREF(oid) IS OF (ONLY Person, Student);
|
|
向下强制转型返回类型的 trEAT...AS
:DB2 强制要求方法调用上的类型安全。也就是说,在执行官(executive)中定义的方法不能在一般雇员(employee)中调用。在下面的示例中,为了允许任何出现的 executive 调用方法,我们告诉 DB2 暂时假设每一个 manager 都是一个 executive。
SELECT ID, trEAT (deref(manager) AS executive)..total_comp() AS total_comp FROM dept_table
WHERE DEREF(manager) IS OF ( ONLY executive);
|
更复杂的结构
结构化类型可以嵌套到其它类型中。例如,地址(address)类型可以拥有额外的子类型,可能是用于商务地址(business address)和美国商务地址(US business address)。这个地址类型可以嵌入到另一个类型,例如名片(business card)类型。现在,名片类型可以用作一个表的类型或是另一个表的一列。
下面的示例将一个行插入到一个表中,该表包含带有嵌套式结构化类型属性的结构化类型:
INSERT INTO Employee_table (Name, Birthyear, ContactInfo)
VALUES ('Sailesh', '1975',
Business_Card_t()..('Chief Programmer',
BusAddr_t()..(street('555 Bailey Avenue')
..city('San Jose')
..state('CA')
..zip('95141')))
|
为应用程序变换对象
因为结构化类型可以是任意形式、任意长度,这取决于您如何定义这些结构化类型,所以,将类型变换成宿主语言程序能够识别的某些东西由您决定。一般地说,这意味着在将对象传送给应用程序之前,把对象扁平化(flatten)成字符串、BLOB 或 CLOB。在应用程序完成它需要对数据进行的操作之后,将扁平化后的结构插入回数据库之前,必须将它再次变换成对象结构。这些“扁平化”和“反扁平化”过程通过用户定义的称为
变换函数的函数加以控制。目前,您得自己定义满足您的应用程序的期望的变换函数。在以后的发行版中很可能会有缺省的变换函数。在您定义了变换函数之后,DB2 将根据需要恰当地调用变换函数。
应用程序集成
自 1995 年以来,DB2 就不断增强它在对象-关系技术方面的支持。在这些最初的发行版中,其着重点是新数据类型、层次结构和引用以及开发用户定义的功能和方法。所有基本的基础架构的存在都是为了在应用程序中使用这些复杂的数据类型。不过,为了提供编程接口和数据库之间的完全集成环境,也开发了一些标准来提供 DB2 和 Java 之间必要的层。应用这些标准的真正价值在于使这些数据类型易于与面向对象编程语言(尤其是 Java)一起使用。这个部分简要描述这些标准,以及当在 DB2 中实现(计划在将来的发行版中实现)它们时,您能做什么。
通过 JDBC 2.0 的支持与 Java 更好地集成
:在设计允许将结构化类型具体化为 Java 对象的 JDBC 2.0 功能中,IBM 起了主要作用。
仅仅通过使用现有的结果集或预编译语句接口就可以生成 Java 对象:
ResultSet rs = stmt.executeQuery(
"SELECT e..addr FROM Employee e");
rs.next( );
Residence addr = (Residence)rs.getObject(1);
|
通过使用 SQLJ Part 2 与 Java 更好地集成:
SQLJ Part 2 是一个 ANSI 标准,IBM 是其主要开发者,它允许使用 Java 类定义 SQL 类型,这些类型就可以用作表中的列或者是类型表。Java 方法成为 SQL 类型上的 SQL99 方法,这些 Java 方法可以在 SQL 中调用。这里是一个展示由 Java 方法实现 SQL 地址类型的简略示例。
在 Java 端 ...
public class Residence implements
SQLData {
public int door;
public String street;
public String city;
public Residence (int d, String s,
String c) {
door =d;
street = s;
city = c;
}
public String printAddress( ) { ...};
public void changeResidence(String
adr) { ... // parse and update fields
...}
// SQLData implementation
}
|
在 SQL 端 ...
CREATE TYPE Address
EXTERNAL NAME
'Residence'
LANGUAGE JAVA
USING SQLDATA
AS( number INTEGER,
street VARCHAR(100),
city VARCHAR(50))
CONStrUCTOR METHOD Address (d INT, s
VARCHAR(100), c VARCHAR(50))
RETURNS Address
SELF AS RESulT
EXTERNAL NAME 'Residence',
METHOD print() RETURNS VARCHAR(200)
EXTERNAL NAME 'printAddress',
METHOD changeAddress (varchar(200))
RETURNS Address
SELF AS RESulT
EXTERNAL NAME 'changeResidence';
|
上面的映射完成之后,您就可以用 NEW 操作符构造新的地址:
INSERT INTO employees
VALUES('John Doe', NEW Address('555','Bailey Avenue', 'San Jose'))
|
接着,使用 changeAddress Java 方法更新这个地址。
UPDATE employees SET addr =
addr..changeAddress('1234 Parkway Dr., San Leandro')
WHERE name = 'John Doe'
|
总结
DB2 在遵循标准的对象-关系功能实现方面处于领先地位。对象-关系基础架构为关系数据库(一种经验证已为市场所接受的技术)未来的发展提供了基础,它为基于 web 的应用程序、内容丰富数据和与面向对象编程语言的无缝集成提供服务。本文讨论的功能包括巨对象类型、用户定义的区别类型和结构化类型、用户定义的方法和函数、继承、路径表达式、对象视图和索引扩展。计划的对 Java 集成的增强功能使得数据和应用程序对象之间的边界成为实际上无缝的。有了这些增强功能,只要是您能想像到的应用程序,就都能够访问 DB2 数据。
功能核对表
|
功能
|
DB2 UDB V7
| | 大对象 | Ü | | 数据连接 | Ü | | 单值类型 | Ü | | 用户定义的函数 | Ü | | 表函数 | Ü | | 重载 | X | | SQL 路径 | X | | 结构化类型 | X | | 子类型和继承 | X | | 作为列类型的结构化类型 | X | | 可替代性 | X | | 变换函数 | X | | 优化内联表示 | X | | 类型表 | X | | 表层次结构 | X | | 引用类型 | X | | 类型视图(对象视图) | X | | 对象视图层次结构 | X | | 可更新的对象视图层次结构 | X | | 在表达式上索引 | X | | 用户定义的索引类型 | X |
更多信息
DB2 通用数据库™V7,
Application Development Guide。请特别参阅标题为“Object-Relational Programming”的一章。
DB2 通用数据库 V7,
SQL Reference。
Michael J. Carey、Serge Rielau 和 Bennet Vance 所著“Object View Hierarchies in DB2 UDB”。
EDBT2000:478-492,1999
Michael J. Carey、Donald D. Chamberlin、Srinivasa Narayanan、Bennet Vance、Doug Doole、Serge Rielau、Richard Swagerman 和 Nelson Mendonca Mattos 所著“O-O, What's Happening to DB2?”
SIGMOD Conference1999:511-512
Michael J. Carey、Donald D. Chamberlin、Srinivasa Narayanan、Bennet Vance、Doug Doole、Serge Rielau、Richard Swagerman 和 Nelson Mendonca Mattos 所著“O-O, What Have They Done to DB2?”
VLDB1999:542-553
Chen、Weidong 等人所著“High Level Indexing of User-Defined Types”。
Proceedings of the 25th VLDB Conference,爱丁堡,苏格兰,1999
N. M. Mattos、J. Kleewein、M. Tork Roth 和 K. Zeidenstein 所著“From Object-Relational to Federated Databases”,
Datenbanksysteme in Buro, Technik und Wissenschaft。1999 年 3 月 1 日至 3 日:185-209。
关于作者  | |  | IBM 的硅谷实验室工作。她开始时在 DB2 for OS/390 ® 组织工作,在那里她第一次接触到了对象-关系。开始在 SQL 标准小组工作之后,她接触到了 DB2 中更高级的对象-关系功能,因为这项工作的很多语言设计都是提交到 SQL 标准协会的。如果没有实现此项技术的开发小组的帮助,本文可能就不会被撰写出来了。就在最近,Kathy 已经在商业智能小组工作,现在的工作和 IBM 新的信息集成策略有关。您可以通过
krzeide@us.ibm.com与 Kathy Zeidenstein 联系。
|
对本文的评价
|