Java Database Connectivity (JDBC)

JDBC is a callable SQL API for the Java programming language. JDBC is both the official and de facto standard for SQL database access from Java. For the C programming language, the DBMS vendors developed their own proprietary APIs well before the development of ODBC or SQL-CLI API. For Java, the JDBC API was developed by Sun Microsystems as part of a suite of Java APIs, embodied in various Java editions.

As a result, all of the major DBMS products provide Java support via JDBC; there are no important competing APIs.

1. JDBC History and Versions

The JDBC API has been through several major revisions since its original introduction. JDBC 1.0 provided the basic core of data access functionality, including a driver manager to arbitrate connections to multiple DBMS’s, connection management to access individual databases, statement management to send SQL commands to the DBMS, and result set management to provide Java access to the query results.

The JDBC 2.0 API and its incremental versions extended JDBC 1.0, and divided the functionality into a Core API and Extensions API. The 2.0 version added:

  • Batch operations. A Java program can pass many rows of data to be inserted or updated via a single API call, improving performance and efficiency of bulk operations.
  • Scrollable result sets. Like the scrollable cursors provided in other APIs, this new capability permitted both forward and backward motion through query results.
  • Updateable result sets. A Java program can update the database by updating a specific row of query results or inserting a new row through the results.
  • Connection pooling. Connections to the database can be shared across Java programs, reducing the overhead of frequent connecting and disconnecting.
  • Distributed transactions. The API provides the capability to synchronize updates across multiple databases, with all or nothing transactions that span database boundaries.
  • Data sources. A new type of object encapsulates the details of a database connection, reducing the need for an application programmer to understand connection specifics.
  •  Rowsets. An abstraction of query results, rowsets allow query results processing even when a program is disconnected from the source database and later resynchronization.
  • Java Naming & Directory Interface (JNDI) support. Databases and drivers can be named and cataloged in a network directory, and accessed via those directory entries.

The JDBC 3.0 API is a relatively new version of JDBC. It was finalized and formally announced by Sun in February 2002, and packaged as part of Java2 Standard Edition (J2SE) 1.4. New capabilities introduced in the 3.0 version include:

  • Object-relational SQL extensions. The API adds support for abstract data types and the associated capabilities that were added in the SQL:1999 standard.
  • Rowsets. The API allows a partial rollback to a specifically marked savepoint partway through a transaction.
  • Cursor preservation. API options allow cursors to remain open across transactions.
  • Prepared statement metadata. Programs can determine information about prepared statements, such as the number and data types of parameters and of query results columns.

2. JDBC Implementations and Driver Types

JDBC assumes a driver architecture like that provided by the ODBC standard, on which it is broadly based. Figure 19-25 shows the main building blocks. A Java program connects to the JDBC driver manager via the JDBC API. The JDBC system software is responsible for loading one or more JDBC drivers, typically on demand from Java programs that request them. Conceptually, each driver provides access to one particular DBMS brand, making whatever brand-specific API calls and sending the SQL statements needed to carry out the JDBC request. The JDBC software is delivered as a Java package, which is imported into a Java program that wants to use JDBC.

The JDBC specification does not deal with the specific details of how a JDBC driver is implemented. However, since the introduction of JDBC, developers have tended to characterize JDBC drivers into four driver types. The type descriptions assume a client/server connection from the JDBC API (on the client system) to a database server. While this is a common enterprise deployment architecture, it’s worth noting that JDBC is used to access local databases on systems as small as handheld devices; in this context, the driver types have less meaning. The driver types differ in how they translate JDBC calls (method invocations) into specific actions against the DBMS.

A Type 1 driver is also called a JDBC/ODBC bridge, shown in Figure 19-26. The driver translates JDBC calls into a vendor-neutral API, which in practice is always ODBC. The request passes to a specific ODBC driver for the target DBMS. (Optionally, the ODBC driver manager may be eliminated, since the ODBC API to the driver manager is the same as the API to the driver itself.) Ultimately, the ODBC driver calls the DBMS’ proprietary API. If the database is on a local system, the DBMS carries out the request. If it’s on a remote (server) system, the DBMS code on the client is a network access stub, which translates the request into a network message (proprietary to the DBMS) and sends it to the DBMS server.

A Type 1 driver has one significant advantage. Because nearly all popular DBMS products support ODBC, a single Type 1 driver can provide access to dozens of different DBMS brands. Type 1 drivers are widely available, including one that is distributed by Sun.

A Type 1 driver also has several disadvantages. Each JDBC request passes through many layers on its way to and from the DBMS, so a Type 1 driver typically carries a lot of computing overhead and its performance suffers as a result. The use of ODBC as an intermediate stage also may limit the functionality provided by the driver—features of the underlying DBMS that might be able to be delivered via the JDBC interface directly may not be accessible via ODBC. Finally, the ODBC driver required by a Type 1 driver will be delivered in binary form, not as a Java executable. Thus, any given Type 1 driver is specific to the client computer’s hardware and operating system, and will lack the portability of Java.

A Type 2 driver is also called a Native API driver. The driver translates JDBC requests directly into the native API of the DBMS, as shown in Figure 19-27. Unlike the Type 1 driver, there is no ODBC or other vendor-neutral layer involved. If the database is located on the same system as the Java program, the Type 2 driver’s calls to the native API will go directly to the DBMS. In a client/server network, the DBMS code on the client is again a network access stub, and the requests flow over the network in a DBMS-proprietary protocol, as in the Type 1 driver.

Type 2 drivers present a different set of trade-offs than Type 1 drivers. A Type 2 driver has fewer layers, so performance is typically higher. It still has the disadvantage of requiring binary code to be installed on the client system, so each Type 1 driver will still be specific to a hardware architecture and operating system. Unlike a Type 1 driver, a Type 2 driver is also specific to a DBMS brand. If you want to communicate with several different DBMS’, you will need multiple drivers. Finally, it’s worth noting that the Type 1/Type 2 distinction assumes that the native DBMS API is not ODBC.

If a DBMS presents a native ODBC interface, then the use of ODBC does not imply an additional layer, and its Type 2 driver will, in fact, use ODBC to access the DBMS.

A Type 3 driver is a Network-Neutral driver. The driver translates JDBC requests into network messages in a vendor-neutral format, and sends them across the network to the server, as shown in Figure 19-28. On the server, a middleware layer receives the network requests and translates them into calls to the DBMS’ native API. Query results are passed back across the network, again in a vendor-neutral format.

Type 3 drivers once again present a different set of trade-offs. One major advantage claimed for the Type 3 architecture is that the client-side code can be written in Java, using the network interfaces provided by other Java APIs. Notice also that the client-side code is DBMS neutral; it does the same work no matter what the target DBMS on the server. This means that the client-side code is very portable, able to run on any system that supports a Java Virtual Machine (JVM) and Java network APIs. Type 3 drivers share one disadvantage with Type 1 drivers: the use of a vendor-neutral network layer, just like the use of a vendor-neutral ODBC layer, means that some capabilities of the underlying DBMS may be inaccessible through the intermediate layer. A Type 3 architecture also involves a double translation of each JDBC request, just as in Type 1; however, one of the translations takes place on the server system, minimizing the client-side impact.

A Type 4 driver is a Network-Proprietary driver. The driver translates JDBC requests into network messages, but this time in a DBMS-proprietary format, as shown in Figure 19-29. The driver is written in Java, and implements a network client for the DBMS’ networking software, such as Oracle’s SQL*Net. On the server, there is no need for a middleware layer, since the DBMS server already provides support for the DBMS vendor’s own client/server networking. Query results flow back across the network, again in vendor-proprietary format, and supplied back to the requesting program.

Type 4 drivers preserve one of the important advantages of Type 3 drivers. They can be implemented in pure Java, so like Type 3, they are portable across computer hardware and operating systems. However, unlike Type 3 drivers, they are DBMS-specific, so different client-side code is required for each DBMS brand you want to access. A Type 4 architecture involves less overhead on the server system, and may therefore deliver slightly better performance. In practice, the overhead of the network messaging will almost always swamp this advantage, except in very high transaction rate applications.

Figure 19-30 summarizes the four JDBC driver types and shows how they relate to one another. The two columns divide the driver types based on whether they use a vendor-neutral intermediate layer (left column) or translate directly from the JDBC API to a DBMS-proprietary interface. The two rows divide the driver types based on whether the translation to a specific DBMS API occurs on the client side (left column) or on the server side. As the figure shows, each of these two decisions creates trade-offs, and they result in four (2×2) driver types.

3. The JDBC API

Java is an object-oriented language, so it’s probably no surprise that JDBC organizes its API functions around a collection of database-related objects and the methods that they provide:

  • Driver Manager object. The entry-point to JDBC
  • Connection objects. Represent individual active connections to target databases
  • Statement objects. Represent SQL statements to be executed
  • ResultSet objects. Represent the results of a SQL query
  • MetaData objects. Represent metadata about databases, query results, and statements
  • Exception objects. Represent errors in SQL statement execution

These objects have the logical relationship shown in Figure 19-31, based on which objects provide methods to create other objects. The following sections describe each of these objects, and how their methods are used to connect to databases, execute SQL statements, and process query results. A complete explanation of the JDBC API is beyond the scope of this book, but the concepts described should allow you to make effective use of JDBC and to understand the documentation that is delivered with the package.

The DriverManager object is the main interface to the JDBC package. Some of the most important methods that it provides are shown in Table 19-14. After loading the JDBC driver class that you want to use (typically using the Class.forName() method), your program will ask the DriverManager object to connect you to that specific driver and a specific database with the getConnection() method:

// Create a connection to the Oracle JDBC driver

String url = “… will vary depending on OS, etc.”

String user = “Scott”;

String pswd = “Tiger”;

Connection dbconn =

DriverManager.getConnection(url, user, pswd);

The getConnection() method returns an object, the Connection object, which embodies the connection that has just been created and the database on the other end of that connection. Other DriverManager methods provide programmatic control over connection timeouts, switch on JDBC call logging for debugging, and other utility functions. If it encounters an error while attempting to make the connection, the DriverManager object will throw an exception. Error handling is described in the “Error Handling in JDBC” section later in this chapter.

3.1. JDBC Basic Statement Processing

The major functions of the JDBC Connection object are to manage the connection to the database, to create SQL statements for processing by that database, and to manage transactions over the connection. Table 19-15 shows the Connection object methods that provide these functions. In most simple JDBC programs, the next step after a connection has been established will be to call the Connection object’s createStatement() method to create a Statement object.

The major function of a Statement object is to actually execute SQL statements. Table 19-16 shows the Statement object methods that you use to control statement execution. There are several different executed methods, depending on the specific type of SQL statement. Simple statements that do not produce query results (e.g., UPDATE, DELETE, INSERT, CREATE TABLE) can use the executeUpdate method. Queries use the executeQuery() method, because it provides a mechanism for returning the query results. Other execute methods support prepared SQL statements, statement parameters, and stored procedures.

To illustrate the basic use of Connection and Statement objects, here is a simple Java program excerpt that creates a connection to a database, performs two database updates, commits the changes, and then closes the connection.

// The connection object and strings we will use Connection dbconn;    

// the database connection

String str1 = “UPDATE OFFICES SET TARGET = 0”;

String str2 = “DELETE FROM SALESREPS WHERE EMPL_NUM = 106”;

<code in here creates the connection>

// Create a statement object for executing SQL

Statement stmt = dbconn.createStatement();

// Update the OFFICES table with the statement object

stmt.executeUpdate(str1);

// Update the SALESREPS table with the statement object

stmt.executeUpdate(str2);

// Commit the changes to the database

dbconn.commit();

// Update the SALESREPS table using the same statement object

stmt.executeUpdate(str2);

// Finally, close the connection

dbconn.close();

As the example shows, the SQL transaction-processing operations (commit and rollback) are handled by method calls to the Connection object, rather than by executing COMMIT and ROLLBACK statements. This allows the JDBC driver to know the status of the transactions that it is processing without examining the specific SQL being executed. JDBC also supports an autocommit mode, in which every statement is treated as an individual transaction. A Connection object method also controls this option.

Note that the Connection and Statement methods called in this program excerpt can cause errors, and the excerpt does not show any error-handling code. If an error occurs, the JDBC driver will throw a SQLException exception. Normally, an excerpt like the previous one (or parts of it) will appear within a try / catch structure to handle the possible exception. For simplicity, the enclosing try / catch structure is suppressed in this and the next several examples. Error-handling techniques are described in the “Error Handling in JDBC” section later in this chapter.

3.2. Simple Query Processing

As with the other SQL APIs and embedded SQL, query processing requires an additional mechanism beyond those used for database updates to handle the returned query results. In JDBC, the ResultSet object provides that additional mechanism. To execute a simple query, a Java program invokes the executeQuery() method of a Statement object, passing the text of the query in the method call. The executeQuery() method returns a ResultSet object that embodies the query results. The Java program then invokes the methods of this ResultSet object to access the query results, row by row and column by column. Table 19-17 shows the methods provided by the ResultSet object.

Here is a very simple Java program excerpt that shows how the objects and methods you have seen so far combine to perform simple query processing. It retrieves and prints out the office number, city, and region for each office in the OFFICES table:

// The connection object, strings and variables

Connection dbconn;      // the database connection

Int num;           // returned office number

String city;       // returned city

String reg;        // returned region

String str1 = “SELECT OFFICE, CITY, REGION FROM OFFICES”

<code in here creates the connection>

// Create a statement object for executing the query

Statement stmt = dbconn.createStatement();

// Carry out query – method returns a ResultSet object

ResultSet answer = stmt.executeQuery(strl);

// Loop through ResultSet a row at a time

while (answer.next()) {

// Retrieve each column of data

num = answer.getInt(“OFFICE”);

city = answer.getString(“CITY”);

reg = answer.getString(3);

// Print the row of results

System.out.println(city + ” ” + num + ” ” + reg);

}

// Explicitly close the cursor and connection

answer.close();

dbconn.close();

The methods used are straightforward and parallel the query-processing steps already seen for embedded SQL and C/C++ APIs. The ResultSet object maintains a cursor to note its current position within the query results. Its next method advances the cursor, row by row, through them. There is an explicit JDBC get method call to retrieve each column of data for each row. Java’s strong typing and memory-protection schemes make this approach a requirement, but it carries significantly higher overhead than the C/C++ approach of binding program variables and having the database API automatically populate those variables when a next row is fetched. Finally, the close method call ends query processing.

The example also shows the two alternative methods for specifying which column’s value should be retrieved by each get method call. You can specify the name of the column to be retrieved (used for the OFFICE and CITY columns), or its ordinal position within the columns of results (used for the REGION column). JDBC delivers this capability by overloading each of the get methods—one version takes a string (column name) argument; the other takes an integer (column number) argument.

3.3. Using Prepared Statements in JDBC

The executeQuery() and executeUpdate() methods of the Statement object provide a dynamic SQL capability. They parallel the SQLExecDirect() call in the CLI standard. The database on the other end of the JDBC connection doesn’t know in advance which SQL text will be presented when the execute method is called. It must parse the statement on the fly and determine how to execute it. The dynamic SQL approach makes this part of the JDBC interface quite easy to use, but it creates the high overhead usually associated with dynamic SQL for the underlying DBMS. For high transaction rate applications where performance is important, an alternative prepared statement interface is more appropriate.

The prepared statement approach uses the same concepts as the PREPARE / EXECUTE statements of embedded dynamic SQL and the SQLPrepare() and SQLExecute() calls of the CLI standard. A SQL statement that is to be executed repeatedly (such as an UPDATE statement that will be used on many rows or a query that will be executed hundreds of times during a program) is first prepared by passing it to the DBMS for parsing and analysis. Later, the statement may be executed repeatedly with very little overhead. You can vary the specific values used by the statement during each execution by passing parameter values for the execution. For example, you can change the values to be used for each UPDATE operation, or change the value to be matched in the WHERE clause of a query using parameters.

To use a prepared statement with JDBC, your program invokes the prepareStatement() method on a connection instead of the createStatement() method. Unlike createStatement(), the prepareStatement() method takes an argument—a string containing the SQL statement that is to be prepared. Within the statement string, parameters to be supplied at statement execution are indicated by a question mark (?), which serves as a parameter marker. A parameter can be used within the statement anywhere that a constant could legally appear in the statement. The prepareStatement() method returns a PreparedStatement object, which includes some additional methods beyond those provided by a Statement object. Table 19-18 shows some of these additional methods, nearly all of which are for parameter processing.

The additional set() methods of the PreparedStatement object take two parameters. One indicates the parameter number for which a value is being supplied.

The other provides the parameter value itself. With these methods, the typical sequence for JDBC prepared statement processing can be summarized as follows:

  1. The Java program establishes a connection to the DBMS in the usual way.
  2. The program calls the prepareStatement() method with the text of the statement to be prepared, including parameter markers. The DBMS analyzes the statement and creates an internal, optimized representation of the statement to be executed.
  3. Later, when it’s time to execute the parameter statement, the program calls one of the set methods in Figure 19-18 for each parameter, supplying a value for the parameter.
  4. When all parameter values have been supplied, the program calls executeQuery or executeUpdate to execute the statement.
  5. The program repeats Steps 3 and 4 over and over (typically dozens or hundreds of times or more), varying the parameter values. If a particular parameter’s value does not change from one execution to the next, the set method does not need to be recalled.

Here is a program excerpt that illustrates the technique:

// The connection object, strings and variables

Connection dbconn;      // the database connection

String city;        // returned city

String str1 = “UPDATE OFFICES SET REGION = ? WHERE MGR = ?”;

String str2 = “SELECT CITY FROM OFFICES WHERE REGION = ?”;

<code in here creates the connection>

// Prepare the UPDATE statement

PreparedStatement pstmtl = dbconn.prepareStatement(strl);

// Prepare the query

PreparedStatement pstmt2 = dbconn.prepareStatement(str2);

// Set parameters for UPDATE statement & execute it

pstmt1.setString(1,”Central”);

pstmt1.setInt(2,108);

pstmt1.executeUpdate();

// Reset one of the parameters and execute again, then commit

pstmt1.setInt(2,104);

pstmt1.executeUpdate();

dbconn.commit()/

// Set parameter for query & execute it

pstmt2.setString(1,”Central”);

ResultSet answer = pstmt2.executeQuery();

// Loop through ResultSet a row at a time while (answer.next()) {

// Retrieve each column of data city = answer.getString(l);

// Print the row of results

System.out.println(“Central city is ” + city);

}

answer.close();

// Set a different parameter for query & execute it pstmt2.setString(1,”Eastern”);

ResultSet answer = pstmt2.executeQuery();

// Loop through ResultSet a row at a time while (answer.next()) {

// Retrieve each column of data city = answer.getString(l);

// Print the row of results

System.out.println(“Eastern city is ” + city);

}

answer.close();

// Done – close the connection

dbconn.close();

3.4. Using Callable Statements in JDBC

The last several sections described how JDBC supports dynamic SQL statement execution (via the Statement object created by the createStatement() method) and prepared SQL statements (via the PreparedStatement object created by the prepareStatement() method). JDBC also supports the execution of stored procedures and stored functions through a third type of statement object, the CallableStatement object created by the prepareCall() method.

Here is how a Java program invokes a stored function or stored procedure using JDBC:

  1. The Java program invokes the prepareCall() method, passing it a SQL statement that invokes the stored routine. Parameters to the call are indicated by parameter markers within the statement string, just as they are for a prepared statement.
  2. The method returns a CallableStatement object.
  3. The Java program uses the set() methods of the CallableStatement object to specify parameter values for the procedure or function call.
  4. The Java program uses another method of the CallableStatement object to specify the data types of returned values from the stored procedure or function.
  5. The Java program invokes one of the CallableStatement object’s executed methods to actually make the call to the stored procedure.
  6. Finally, the Java program invokes one or more of the CallableStatement object’s get() methods to retrieve the values returned by the stored procedure (if any) or the return value of the stored function.

A CallableStatement object provides all of the methods of a PreparedStatement, listed in Tables 19-16 and 19-18. The additional methods that it provides for registering the data types of output or input/output parameters, and for retrieving the returned values of those parameters after the call, are shown in Table 19-19.

A short example is the best way to illustrate the technique for calling a stored pro­cedure and stored function. Suppose the sample database contains a stored procedure defined like this:

CREATE PROCEDURE CHANGE_REGION

(IN OFFICE INTEGER,

OUT OLD_REG VARCHAR(10),

IN NEW_REG VARCHAR(10))

that changes the region of an office, as requested by the two input parameters, and returns the old region as an output parameter and a stored function, defined like this:

 CREATE FUNCTION GET_REGION

(IN OFFICE INTEGER)

RETURNS VARCHAR(10)

that returns the region of an office, given its office number. This Java program excerpt shows how to invoke the stored procedure and stored function using JDBC:

// The connection object, strings and variables

Connection dbconn;      // the database connection

String str1 = “{CALL CHANGE_REGION(?, ?, ?)}”;

String str2 = “{? = CALL GET_REGION(?)}”;

String oldreg;              // returned former region

String ansreg;              // returned current region

<code in here creates the connection>

// Prepare the two statements

CallableStatement cstmt1 = dbconn.prepareCall(str1);

CallableStatement cstmt2 = dbconn.prepareCall(str2);

// Specify param values & returned data types for stored procedure call

cstmt1.setInt(1,12); // call with office number 12 (Chicago)

cstmt1.setString(3,”Central”); // and new Central region

cstmt1.registerOutParameter(2,Types.VARCHAR); // returns a varchar param

// Go ahead and execute the call to the stored procedure

cstmt1.executeUpdate();

oldreg = cstmt.getString(2); // returned (2nd) param is a string

// Specify param values & returned data type for stored function call

cstmt2.setInt(1/12); // call with office number 12 (Chicago)

cstmt2.registerOutParameter(1/Types.VARCHAR); // fcn returns a varchar

// Go ahead and execute the call to the stored function

cstmt2.executeUpdate();

ansreg = cstmt.getString(1); // returned value (1st param) is a string

// Done – close the connection

dbconn.close();

Note that the call invocations of the stored procedure or function in the statement strings are enclosed in curly brackets. The input parameters passed to a stored procedure or function are handled exactly the same way as parameters for a prepared statement. Output parameters from a stored procedure require some new machinery: the registerOutParameter() method call to specify their data types, and calls to the get() methods to retrieve their values after the call is complete. These are summarized in Table 19-19. Input/output parameters for a stored procedure require both that values be passed into the procedure call, using the set() methods, and that the output data type be specified with registerOutParameter() and the returned data be retrieved with the get() methods.

For a stored function, there are only input parameters, and the set() methods are once again used. The return value of the function is specified with a parameter marker in the prepared statement string. Its data type is registered, and its value is retrieved, just as if it were a regular output parameter.

3.5. Error Handling in JDBC

When an error occurs during JDBC operation, the JDBC interface throws a Java exception. Most SQL statement execution errors throw a SQLException. The error can be handled via the standard Java try / catch mechanism. When a SQLException error occurs, the catch() method is called with a SQLException object, some of whose methods are summarized in Table 19-20.

The SQLException methods allow you to retrieve the error message, SQLSTATE error code, and DBMS-specific error code associated with the error. It is possible for a single JDBC operation to create more than one error. In this case, the errors are available to your program in sequence. Calling getNextException() on the first reported error returns a SQLException for the second exception, and so on, until there are no more exceptions to be handled.

3.6. Scrollable and Updateable Cursors in JDBC

Just as scrollable cursors have been added to the ANSI/ISO SQL standards, scrollable cursors have been added to JDBC result sets in later versions of the specification. You indicate that you want a query to produce results that are scrollable through a parameter to the executeQuery method. If you specify scrollability, the ResultSet returned by the executeQuery call offers some additional methods for cursor control. The important methods are listed in Table 19-21.

In addition to scrollable result sets, later versions of the JDBC specification added support for updateable result sets. This capability corresponds to the UPDATE…WHERE CURRENT OF capability in embedded SQL. It allows an update to specific columns of this row, which is indicated by the current position of a cursor. Updateable result sets also allow new rows of data to be inserted into a table via a result set.

3.7. Retrieving Metadata with JDBC

The JDBC interface provides objects and methods for retrieving metadata about databases, query results, and parameterized statements. A JDBC Connection object provides access to metadata about the database that it represents. Invoking its getMetaData() method returns a DatabaseMetaData object, described in Table 19-22. Each method listed in the table returns a result set, containing information about a type of database entity: tables, columns, primary keys, and so on. The result set can be processed using the normal JDBC query results processing routines. Other metadata access methods provide information about the database product name supported on this connection, its version number, and similar information.

Metadata information about query results can also be very useful. A ResultSet object provides a getMetaData method that can be invoked to obtain a description of its query results. The method returns a ResultSetMetaData object, described in Table 19-23. The methods let you determine how many columns there are in the query results, and the name and data type of each column, identified by their ordinal position within the query results.

Finally, metadata information about the parameters used in a prepared SQL statement or a prepared call to a stored procedure can also be useful. The PreparedStatement and the CallableStatement objects both provide a getParameterMetaData() method that retrieves this information. The method returns a ParameterMetaData object, described in Table 19-24. Invoking the methods of this object provides information about how many parameters are used in the statement, their data types, whether each parameter is an input, output or input/output parameter, and similar information.

3.8. Advanced JDBC Capabilities

JDBC 2.0 and JDBC 3.0 introduced several capabilities that extend the basic database access functionality of JDBC. JDBC data sources, first introduced in JDBC 2.0, provide a higher-level method for finding available drivers and databases and connecting to them. They mask the details of making a connection from the Java application programmer. Basically, a data source is identified with some external directory or catalog that is able to translate logical entity names into specific details. Using a data source, the application programmer can specify a target database by an abstract name, and have the directory in conjunction with the JDBC software handle the details of connections.

JDBC rowsets are another advanced concept enhanced and extended in the JDBC revisions. A rowset extends the concept of a JDBC result set, which you will recall represents a set of query results. Beyond the query results themselves, a rowset encapsulates information about the underlying source database, the connection to the database, its user name and password, and so on. The rowset retains its identity independent of an active connection to the database. Thus, a rowset may exist in a disconnected state, and it can be used to reestablish a connection to the database. When connected to the database, the rowset can contain query results like a result set.

Rowsets have several other characteristics and capabilities. A rowset meets the requirement for a JavaBeans component, and when connected to a database, provides a way to make a result set look like an Enterprise Java Bean (EJB). Rowsets hold tabular row/column query results, and those results can be retrieved, navigated, and even updated whether the rowset is currently connected to the source database or not. If disconnected updates are made, resynchronization is implied when the rowset once again is connected to the source database. Finally, the concept of a rowset is not necessarily tied to SQL and relational databases. The data in a rowset can conceptually come from any tabular data source, such as a personal computer spreadsheet or even a table within a word processing document. A complete discussion of JDBC rowsets is beyond the scope of this book; see the JDBC documentation at http://www.java.sun.com/ products/jdbc/ for more information about this and other JDBC capabilities.

Source: Liang Y. Daniel (2013), Introduction to programming with SQL, Pearson; 3rd edition.

Leave a Reply

Your email address will not be published. Required fields are marked *