Contents | Prev | Next JDBCTM Guide: Getting Started


7 Persistence for Java Objects

The JDBC 1.0 API provided some support for storing Java objects and retrieving Java objects from a database via the getObject() and setObject() mechanism. The JDBC 2.0 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 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 JDBC 2.0 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 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 JDBC. 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 JDBC. In fact, since there is currently not a standard, agreed upon syntax for SQL queries that reference Java types, JDBC 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 JDBC. As an aside, we note that the JDBC 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.

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 JDBC. 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 JDBC. 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 JDBC code could be used if the Employee class was being mapped to an SQL user-defined type.

7.3     Additional metadata

The JDBC 2.0 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:

  • TYPE_NAME String => data source specific name (may be null)
  • DATA_TYPE short => java.sql.Types.JAVA_OBJECT
  • 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.

    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 2.0 API doesn't provide any special support for loading the Java class files that correspond to Java objects being stored in a database. A JDBC 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 2.0 API assumes that the bytecodes for objects stored in the database are loaded via the usual Java language mechanism.



    Contents | Prev | Next
    jdbc@eng.sun.com or jdbc-business@eng.sun.com
    Copyright © 1996, 1997 Sun Microsystems, Inc. All rights reserved.