Contents | Prev | Next | JDBCTM Guide: Getting Started

## 7 Persistence for Java Objects

The JDBC 1.0 API provided some support for storing objects and retrieving Java objects from a database via the `getObject()` and `setObject()` mechanism. The new JDBC API enhances the ability of a JDBC driver to implement persistence for Java objects in general, by providing new metadata capabilities that can be used to retrieve a description of the Java objects that a data source contains. Instances of a Java programming language class (Java class) can be stored in a database as serialized Java objects, or in some other vendor specific format. If object serialization is used then references between objects can be treated according to the rules specified by Java object serialization.

The new JDBC API features described in this chapter are intended to support a new generation of Java-aware database management systems, termed Java-relational DBMSs. A Java-relational DBMS extends the type system of a database with Java object types and allows users to write queries that reference these types. Several database vendors are creating products with Java-relational capabilities. The mechanisms described in this chapter are optional. JDBC drivers that do not support the capabilities described in this chapter are not required to implement them.

Lets take a look at how a typical application written in the Java programming language (Java application) can make use of the JDBC API to store and retrieve Java objects.

### 7.1 Retrieving Java objects

The example below shows how objects can be retrieved using the JDBC API. The example query references a table, `PERSONNEL`, that contains a column called `Employee` containing instances of the Java class `Employee`. Here, the column name, `Employee`, and the Java class name are the same, but this is not required by the JDBC API. In fact, since there is currently not a standard, agreed upon syntax for SQL queries that reference Java programming language types (Java types), the JDBC API does not mandate the use of any particular query syntax.

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

The example selects all of the `Employee` instances from the `PERSONNEL` table. The `ResultSet.next()` method is called to position the result set to the first row containing an `Employee`. The example application then obtains an `Employee` instance by calling `ResultSet.getObject()`. This causes the JDBC driver to construct an instance of the `Employee` class, possibly by deserializing a serialized object instance, and return the instance as a `java.lang.Object` which the application then narrows to an `Employee`.

Note that the example above does not contain any additions to the JDBC 1.0 API aside from possibly requiring some form of extended SQL query syntax which is not specified by the JDBC API. As an aside, we note that the JDBC technology based code shown above can also be used to retrieve data of an SQL user-defined type that is being mapped to a Java class. The details on how this is done are specified in a later chapter.

### 7.2 Storing Java objects

The following example code illustrates the process of updating a Java object and making the updated copy of the object persistent using JDBC technology.

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

The example gives an employee a 50% raise. First, the `Employee.setSalary()` method is called to update the value of the employee's salary. Note that the semantics of methods on the `Employee` class are not specified by the JDBC API. Here, we assume that the `Employee` class is an ordinary Java class, so calling `Employee.setSalary()` just changes the value of some private data field contained in the `Employee` instance. Calling `Employee.setSalary()` does not update the database, for example, although an alternative implementation could do this, in effect making database updates `transparent' to applications that use the `Employee` class.

Next, a `PreparedStatement` object is created using an extended SQL UPDATE command -the query syntax used in the example is again not mandated by the JDBC API. The UPDATE command specifies that the `Employee` column in the `PERSONNEL` table is to be changed for a specified row. `PreparedStatement.setObject()` is used to pass the `Employee` object to the prepared statement, and the `executeUpdate()` method updates the `Employee` value stored in the database.

Note once again that the example above does not involve any syntactic additions to the JDBC 1.0 API. In addition, the same code could be used if the Employee class was being mapped to an SQL user-defined type.

### 7.3 Additional metadata

The new JDBC API contains new metadata support that allows an application to obtain a complete description of the Java objects that are stored in a data source.

#### 7.3.1 Identifying Java objects

A new type code, `JAVA_OBJECT`, has been added to `java.sql.Types` to denote a Java object type. The `JAVA_OBJECT` type code is returned by methods such as `DatabaseMetaData.getTypeInfo()` and`DatabaseMetaData.getColumns()`. For example, if a DBMS supports types that can be a Java class, `DatabaseMetaData.getTypeInfo()` would return a result set containing the following entry:

1. TYPE_NAME String => data source specific name (may be null)
2. DATA_TYPE short => `java.sql.Types.JAVA_OBJECT`
3. etc.

The TYPE_NAME column contains the data source specific term for a Java object, such as "JavaObject", "Serialized" etc. TYPE_NAME may be null.

#### 7.3.2 Retrieving schema-specific Java type descriptions

A Java class is typically registered with a particular database schema before it is used in defining the schema's tables. Information on schema-specific user-defined types- of which `JAVA_OBJECT` types are one particular kind-can be retrieved by calling the `DatabaseMetaData.getUDTs()` method. For example,

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

returns descriptions of all the Java object types defined in the `catalog-name.schema- name` schema`.` If the driver does not support UDTs or no matching UDTs are found then an empty result set is returned.

Each type description has the following columns:

TYPE_CAT | String => the type's catalog (may be null)
TYPE_SCHEM | String => the type's schema (may be null)
TYPE_NAME | String => the database type name
JAVA_CLASS | String => a Java classname
DATA_TYPE | short => value defined in `java.sql.Types`, e.g. JAVA_OBJECT
REMARKS | String => explanatory comment on the type

The TYPE_CAT, TYPE_SCHEM, DATA_TYPE, and REMARKS columns should be self-explanatory. The TYPE_NAME is, in effect, the SQL type name. This is the name used in a CREATE TABLE statement to specify a column of this type.

When DATA_TYPE is `JAVA_OBJECT`, the JAVA_CLASS is the fully qualified Java class name of the Java class associated with TYPE_NAME. All values actually stored in a TYPE_NAME column must be instances of this class or one of its subclasses. Instances of this class or a subclass are materialized by the JDBC driver when values are fetched from a TYPE_NAME column by an application that uses JDBC technology.

The `DatabaseMetaData.getUDTs()` method also accepts a fully qualified SQL name as its third parameter. In this case the catalog and schema pattern parameters are ignored. The fully qualified SQL name may contain wildcards. For example, the code sample below is equivalent to the previous example,

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

Here we have assumed that the `.' character is used to separate the elements of a fully qualified name. Note that since the format of fully qualified names may vary between database systems, one should generally not hardcode fully qualifed names as in the example above. The `DatabaseMetaData` interface provides information about the format of fully qualified names that is supported by a particular JDBC driver.

#### 7.3.3 Retrieving the Java class object

The JDBC API doesn't provide any special support for loading the Java class files that correspond to Java objects being stored in a database. An application should be able to obtain the class object that corresponds to an object in the database by calling `Class.forName()` and passing the class name as a parameter. In other words, the JDBC API assumes that the bytecodes for objects stored in the database are loaded via the usual Java programming language mechanism.

Contents | Prev | Next

Copyright © 1996-1999 Sun Microsystems, Inc. All rights reserved.