目录 | 上一页 | 下一页 JDBCTM 指南:入门


7 对 Java 对象的持久性

JDBC 1.0 API 提供了一些对存储 Java 对象和经由 getObject()setObject() 机制从数据库检索 Java 对象的支持。JDBC 2.0 API 通过提供新型的元数据功能(可以使用元数据功能来检索对数据源所含 Java 对象的描述)从总体上增强了 JDBC 驱动程序实现 Java 对象持久性的能力。Java 类的实例可以作为可序列化的 Java 对象(或其它某种特定于厂商的格式)存储在数据库中。如果采用了对象序列化,则可以根据 Java 对象序列化所指定的规则处理对象之间的引用。

本章所述的 JDBC 2.0 API 功能可支持新一代的能感知 Java 的数据库管理系统,称为 Java 关系式 DBMS。Java 关系式 DBMS 用 Java 对象类型扩展了数据库的类型系统,同时允许用户编写引用这些类型的查询。现在有几家数据库厂商正在创建具有 Java 关系式能力的产品。本章所述的各种机制是可选的。不支持本章所述功能的 JDBC 驱动程序不需要实现这些功能。

让我们先看看典型的 Java 应用程序如何利用 JDBC API 来存储和检索 Java 对象。

7.1 检索 Java 对象

下例显示了利用 JDBC 如何检索对象。示例查询引用了 PERSONNEL 表,而表中包含了称为 Employee 的列,列中包含 Java 类 Employee 的实例。此处,列名 Employee 和 Java 类名相同,但是这并非是 JDBC 所要求的。事实上,由于目前引用 Java 类型的 SQL 查询没有公认的标准语法,所以 JDBC 并没有要求必须使用任何特定的查询语法。

ResultSet rs = stmt.executeQuery(
	"SELECT Employee FROM PERSONNEL");
rs.next();
Employee emp = (Employee)rs.getObject(1);

本例从 PERSONNEL 表中选择了所有的 Employee 实例。调用 ResultSet.next() 方法将结果集定位到包含 Employee 的第一行。然后,示例应用程序通过调用 ResultSet.getObject() 获得 Employee 实例。这将导致 JDBC 驱动程序(或许是通过恢复序列化的对象实例)构造 Employee 类的实例,然后将实例作为 java.lang.Object 返回,而应用程序将其限定为 Employee

请注意:上例中没有包含对 JDBC 1.0 API 的增加部分,而只是可能需要一些 JDBC 未规定的扩展的 SQL 查询语法格式。另外,我们注意到以上所示的 JDBC 代码还可用来检索映射成 Java 类的 SQL 自定义类型的数据。稍后一章中我们将详细讨论这一点。

7.2 存储 Java 对象

下例说明了利用 JDBC 更新 Java 对象及使得对象的更新副本能持久的过程。

emp.setSalary(emp.getSalary() * 1.5);
PreparedStatement pstmt = con.preparedStatement(
"UPDATE PERSONNEL SET Employee = ? WHERE Employee.no = 1001");
pstmt.setObject(1, emp);
pstmt.executeUpdate();


下例给某雇员的工资上涨了 50% 。它首先调用 Employee.setSalary() 方法来更新该雇员的工资额。请注意:JDBC 并没有规定 Employee 类上的方法的语义。此处,我们假定 Employee 类是一般的 Java 类,因此调用 Employee.setSalary() 只是改变 Employee 实例中某些私有数据域的值。例如,调用 Employee.setSalary() 并不会更新数据库,尽管另外一种替代实现可以做到这一点,实际上也就使数据库更新对于使用 Employee 类的应用程序成为“透明的”。

接着,它将利用扩展的 SQL UPDATE 命令(本例中所用的查询语法也不是 JDBC 必需的)来创建 PreparedStatement 对象。UPDATE 命令表示要改变 PERSONNEL 表中指定行的 Employee 列。PreparedStatement.setObject() 的作用是将 Employee 对象传递给预先准备好的语句,而 executeUpdate() 方法更新存储在数据库中的 Employee 值。

请再次注意:上例并没有涉及 JDBC 1.0 API 没有的语法增加部分。另外,如果要将 Employee 类映射到 SQL 自定义类型,仍可以使用与此相同的 JDBC 代码。

7.3 附加元数据

JDBC 2.0 API 包含了一种新型的元数据支持,可以使应用程序获得对存储在数据源中的 Java 对象的完整描述。

7.3.1 标识 Java 对象

java.sql.Types 中新增了一种类型代码 JAVA_OBJECT,可用来表示 Java 对象类型。JAVA_OBJECT 类型代码是由诸如 DatabaseMetaData.getTypeInfo() DatabaseMetaData.getColumns() 的方法返回的。例如,如果 DBMS 支持是 Java 类的类型,则 DatabaseMetaData.getTypeInfo() 将返回包含有以下项的结果集:

TYPE_NAME 列包含了 Java 对象的数据源特定的术语,例如“JavaObject”、“Serialized(序列化的)”等等。TYPE_NAME 可以为空。

7.3.2 特定于检索架构的 Java 类型描述

在用 Java 类来定义架构的表之前,通常用特定的数据库架构来注册 Java 类。可以通过调用 DatabaseMetaData.getUDTs() 方法来检索有关特定于架构的自定义类型(JAVA_OBJECT 类型是其中的一种)的信息。例如,

int[] types = {Types.JAVA_OBJECT};
ResultSet rs = dmd.getUDTs("catalog-name", "schema-name",
	"%", types);

将返回在 catalog-name.schema- name 架构中定义的所有 Java 对象的描述。如果驱动程序不支持 UDT 或没有找到匹配的 UDT,则返回空结果集。

每种类型描述都有以下几列:

TYPE_CAT String => 类型的目录(可以为空)
TYPE_SCHEM String => 类型的架构(可以为空)
TYPE_NAME String => 数据库类型名称
JAVA_CLASS String => Java 类名称
DATA_TYPE short =>在 java.sql.Types 中定义的数值,例如 JAVA_OBJECT
REMARKS String => 类型的说明性注释

TYPE_CATTYPE_SCHEMDATA_TYPEREMARKS 各列应该是无需加以解释的。TYPE_NAME 实际上就是 SQL 类型名称。在 CREATE TABLE 语句中就使用该名称来指定这种类型的列。

DATA_TYPEJAVA_OBJECT 时,则 JAVA_CLASS 就是与 TYPE_NAME 相关联的 Java 类的全限定的 Java 类名。实际上存储在 TYPE_NAME 列中的所有值必须是该类或其子类的实例。当通过使用 JDBC 的应用程序从 TYPE_NAME 列中取出数值时,将由 JDBC 驱动程序实现该类或子类的实例。

DatabaseMetaData.getUDTs() 方法也接受 SQL 全限定名作为其第三个参数。这种情况下,将忽略目录和架构模式参数。SQL 全限定名可能包含通配符。例如,下列代码示例与前一例等同。

int[] types = {Types.JAVA_OBJECT};
ResultSet rs = dmd.getUDTs(null, null,
	"catalog-name.schema-name.%", types);

此处,我们假设字符“.”是用来分隔全限定名的各组成元素。请注意全限定名的格式在数据库之间可能会有所不同,所以通常不能象上例一样对全限定名进行硬编码。DatabaseMetaData 接口提供了有关特定 JDBC 驱动程序所支持的全限定名格式的信息。

7.3.3 检索 Java 类对象

JDBC 2.0 API 没有为加载 Java 类文件(对应于存储在数据库中的 Java 对象)提供任何特殊的支持。JDBC 应用程序通过调用 Class.forName() 并且将类名作为参数传递,可以获得对应于数据库中的对象的类对象。换句话说,JDBC 2.0 API 假定存储在数据库中的对象的字节码是经由通用 Java 语言架构加载的。



目录 | 上一页 | 下一页


jdbc@eng.sun.comjdbc-business@eng.sun.com

版权所有 © 1996, 1997 Sun Microsystems, Inc. 保留所有权利