Contents | Prev | Next | JDBCTM Guide: Getting Started |
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.
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.
The example gives an employee a 50% raise. First, theemp.setSalary(emp.getSalary() * 1.5); PreparedStatement pstmt = con.preparedStatement( "UPDATE PERSONNEL SET Employee = ? WHERE Employee.no = 1001"); pstmt.setObject(1, emp); pstmt.executeUpdate();
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.
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:
java.sql.Types.JAVA_OBJECT
The TYPE_NAME column contains the data source specific term for a Java object, such as "JavaObject", "Serialized" etc. TYPE_NAME may be null.
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,
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. Theint[] types = {Types.JAVA_OBJECT};
ResultSet rs = dmd.getUDTs(null, null,
"catalog-name.schema-name.%", types);
DatabaseMetaData
interface provides information about the format
of fully qualified names that is supported by a particular JDBC driver.
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.