Whole document tree
5 Result Set EnhancementsThis chapter discusses the new functionality that has been added to result sets. The goal of the enhancements is to add two new basic capabilities to result sets: scrolling and updat ability. Several methods have also been added to enable a JDBC driver to deliver improved performance when processing results. A variety of examples are included to illustrate the new features.5.1 ScrollingA result set created by executing a statement may support the ability to move backward (last-to-first) through its contents, as well as forward (first-to-last). Result sets that support this capability are called scrollable result sets. Result sets that are scrollable also support relative and absolute positioning. Absolute positioning is the ability to move directly to a row by specifying its absolute position in the result set, while relative positioning gives the ability to move to a row by specifying a position that is relative to the current row. The definition of absolute and relative positioning in the JDBC API is modeled on the X/Open SQL CLI specification.5.2 Result Set typesThe JDBC 1.0 API provided one result set type-forward-only. The JDBC 2.1 core API provides three result set types: forward-only, scroll-insensitive, and scroll-sensitive. As their names suggest, the new result set types support scrolling, but they differ in their ability to make changes visible while they are open.A scroll-insensitive result set is generally not sensitive to changes that are made while it is open. A scroll-insensitive result set provides a static view of the underlying data it contains. The membership, order, and column values of rows in a scroll-insensitive result set are typically fixed when the result set is created. On the other hand, a scroll-sensitive result set is sensitive to changes that are made while it is open, and provides a `dynamic' view of the underlying data. For example, when using a scroll-sensitive result set, changes in the underlying column values of rows are visible. The membership and ordering of rows in the result set may be fixed- this is implementation defined. 5.3 Concurrency typesAn application may choose from two different concurrency types for a result set: read- only and updatable.A result set that uses read-only concurrency does not allow updates of its contents. This can increase the overall level of concurrency between transactions, since any number of read-only locks may be held on a data item simultaneously. A result set that is updatable allows updates and may use database write locks to mediate access to the same data item by different transactions. Since only a single write lock may be held at a time on a data item, this can reduce concurrency. Alternatively, an optimistic concurrency control scheme may be used if it is thought that conflicting accesses to data will be rare. Optimistic concurrency control implementations typically compare rows either by value or by a version number to determine if an update conflict has occurred. 5.4 PerformanceTwo performance hints may be given to a JDBC 2.1 technology-enabled driver to make access to result set data more efficient. Specifically, the number of rows to be fetched from the database each time more rows are needed can be specified, and a direction for processing the rows-forward, reverse, or unknown-can be given as well. These values can be changed for an individual result set at any time. A JDBC driver may ignore a performance hint if it chooses.5.5 Creating a result setThe example below illustrates creation of a result set that is forward-only and uses read- only concurrency. No performance hints are given by the example, so the driver is free to do whatever it thinks will result in the best performance. The transaction isolation level for the connection is not specified, so the default transaction isolation level of the underlying database is used for the result set that is created. Note that this code is just written using the JDBC 1.0 API, and that it produces the same type of result set that would have been produced by the JDBC 1.0 API.
Connection con = DriverManager.getConnection( "jdbc:my_subprotocol:my_subname"); Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery( "SELECT emp_no, salary FROM employees"); The next example creates a scrollable result set that is updatable and sensitive to updates. Rows of data are requested to be fetched twenty-five at-a-time from the database.
The example below creates a result set with the same attributes as the previous example, however, a prepared statement is used to produce the result set.Connection con = DriverManager.getConnection( "jdbc:my_subprotocol:my_subname"); Statement stmt = con.createStatement( ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); stmt.setFetchSize(25); ResultSet rs = stmt.executeQuery( "SELECT emp_no, salary FROM employees");
The methodPreparedStatement pstmt = con.prepareStatement( "SELECT emp_no, salary FROM employees where emp_no = ?", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); pstmt.setFetchSize(25); pstmt.setString(1, "100010"); ResultSet rs = pstmt.executeQuery(); DatabaseMetaData.supportsResultSetType() can be called to see
which result set types are supported by a JDBC driver. However, an application may
still ask a JDBC driver to create a Statement , PreparedStatement , or CallableStatement
object using a result set type that the driver does not support. In this
case, the driver should issue an SQLWarning on the Connection that produces the
statement and choose an alternative value for the result set type of the statement according
to the following rules:
DatabaseMetaData.supportsResultSetConcurrency() can
be called to determine which concurrency types are supported by a driver. If an application
asks a JDBC driver for a concurrency type that it does not support then the driver
should issue an SQLWarning on the Connection that produces the statement and
choose the alternative concurrency type. The choice of result set type should be made
first if an application specifies both an unsupported result set type and an unsupported
concurrency type.
In some instances, a JDBC driver may need to choose an alternate result set type or concurrency
type for a 5.6 UpdatesA result set is updatable if its concurrency type isCONCUR_UPDATABLE . Rows in an updatable
result set may be updated, inserted, and deleted. The example below updates the
first row of a result set. The ResultSet.updateXXX() methods are used to modify the
value of an individual column in the current row, but do not update the underlying database.
When the ResultSet.updateRow() method is called the database is updated.
Columns may be specified by name or number.
rs.first(); rs.updateString(1, "100020"); rs.updateFloat("salary", 10000.0f); rs.updateRow();
The updates that an application makes must be discarded by a JDBC driver if the application
moves the cursor from the current row before calling The following example illustrates deleting a row. The fifth row in the result set is deleted from the database.
rs.absolute(5); rs.deleteRow();
The example below shows how a new row may be inserted into a result set. The JDBC
API defines the concept of an insert row that is associated with each result set and is
used as a staging area for creating the contents of a new row before it is inserted into
the result set itself. The
Calling
A result set remembers the current cursor position "in the result set" while its cursor is temporarily positioned on the insert row. To leave the insert row, any of the usual cursor positioning methods may be called, including the special methodrs.moveToInsertRow(); rs.updateString(1, "100050"); rs.updateFloat(2, 1000000.0f); rs.insertRow(); rs.first(); ResultSet.moveToCurrentRow()
which returns the cursor to the row which was the current
row before ResultSet.moveToInsertRow() was called. In the example above, ResultSet.first()
is called to leave the insert row and move to the first row of the result
set.
Due to differences in database implementations, the JDBC API does not specify an exact set of SQL queries which must yield an updatable result set for JDBC drivers that support updatability. Developers can, however, generally expect queries which meet the following criteria to produce an updatable result set:
5.7 Cursor movement examplesA result set maintains an internal pointer called a cursor that indicates the row in the result set that is currently being accessed. A result set cursor is analogous to the cursor on a computer screen which indicates the current screen position. The cursor maintained by a forward-only result set can only move forward through the contents of the result set. Thus, rows are accessed sequentially beginning with the first row.
Iterating forward through a result set is done by calling the
The example below positions the cursor before the first row and then iterates forward
through the contents of the result set. The
rs.beforeFirst(); while ( rs.next()) { System.out.println(rs.getString("emp_no") + " " + rs.getFloat("salary")); } Of course, one may iterate backward through a scrollable result set as well, as is shown below.
In this example, thers.afterLast(); while (rs.previous()) { System.out.println(rs.getString("emp_no") + " " + rs.getFloat("salary")); } ResultSet.afterLast() method positions the scrollable result
set's cursor after the last row in the result set. The ResultSet.previous() method is
called to move the cursor to the last row, then the next to last, and so on. ResultSet.previous()
returns false when there are no more rows, so the loop ends after all
of the rows have been visited.
After examining the
This example attempts to iterate forward through a scrollable result set and is incorrect for several reasons. One error is that if// incorrect!!! while (!rs.isAfterLast()) { rs.relative(1); System.out.println(rs.getString("emp_no") + " " + rs.getFloat("salary")); } ResultSet.isAfterLast() is called when the
result set is empty, it will return a value of false since there is no last row, and the loop
body will be executed, which is not what is wanted. An additional problem occurs when
the cursor is positioned before the first row of a result set that contains data. In this case
calling rs.relative(1) is erroneous since there is no current row.
The code sample below fixes the problems in the previous example. Here a call to
if (rs.first()) { while (!rs.isAfterLast()) { System.out.println(rs.getString("emp_no") + " " + rs.getFloat("salary")); rs.relative(1); } } 5.8 Detecting and viewing changesSo far, we have introduced the different result set types and shown a few examples of how a result set of a particular type can be created, updated, and traversed. This section goes into more detail on the differences between result set types, and what these differences mean for an application that uses result sets.The different result set types-forward-only, scroll-insensitive, and scroll-sensitive- provided by the JDBC API vary greatly in their ability to make changes in the underlying data visible to an application. This aspect of result sets is particularly interesting for the result set types which support scrolling, since they allow a particular row to be visited multiple times while a result set is open. 5.8.1 Visibility of changesWe begin the discussion of this topic by describing the visibility of changes at the transaction level. First, note the seemingly obvious fact that all of the updates that a transaction makes are visible to itself. However, the changes (updates, inserts, and deletes) made by other transactions that are visible to a particular transaction are determined by the transaction isolation level. The isolation level for a transaction can be set by calling
where the variablecon.setTransactionIsolation(TRANSACTION_READ_COMMITTED); con has type Connection . If all transactions in a system execute at
the TRANSACTION_READ_COMMITTED isolation level or higher, then a transaction will
only see the committed changes of other transactions. The changes that are visible to a
result set's enclosing transaction when a result set is opened are always visible through
the result set. In fact, this is what it means for an update made by one transaction to be
visible to another transaction.
But what about changes made while a result set is open? Are they visible through the
result set by, for example, calling 5.8.2 Other's changesA scroll-insensitive result set does not make any changes visible that are made by others -other transactions and other result sets in the same transaction-once the result set is opened. The content of a scroll-insensitive result set with respect to changes made by others is static-the membership, ordering, and row values are fixed. For example, if another transaction deletes a row that is contained in a static result set while it is open, the row remains visible. One way to implement a scroll-insensitive result set is to create a private copy of the result set's data.Scroll-sensitive result sets lie at the opposite end of the spectrum. A scroll-sensitive result set makes all of the updates made by others that are visible to its enclosing transaction visible. Inserts and deletes may not be visible, however. Let us define carefully what it means for updates to be visible. If an update made by another transaction affects where a row should appear in the result set-this is in effect a delete followed by an insert-the row may not move until the result set is reopened. If an update causes a row to fail to qualify for membership in a result set-this is in effect a delete-the row may remain visible until the result set is reopened. If a row is explicitly deleted by another transaction, a scroll-sensitive result set may maintain a placeholder for the row to permit logical fetching of rows by absolute position. Updated column values are always visible, however.
The A forward-only result set is really a degenerate case of either a scroll-insensitive or scroll-sensitive result set- depending on how the DBMS evaluates the query that produces the result set. Most DBMSs have the ability to materialize query results incrementally for some queries. If a query result is materialized incrementally, then data values aren't actually retrieved until they are needed from the DBMS and the result set will behave like a sensitive result set. For some queries, however, incremental materialization isn't possible. For example, if the result set is sorted, the entire result set may need to be produced a priori before the first row in the result set is returned to the application by the DBMS. In this case a forward-only result set will behave like an insensitive result set.
For a 5.8.3 A result set's own changesWe have pointed out that the visibility of changes made by others generally depends on a result set's type. A final point that concerns the visibility of changes via an open result set is whether a result set can see its own changes (inserts, updates, and deletes). A JDBC technology application can determine if the changes made by a result set are visible to the result set itself by calling theDatabaseMetaData methods: ownUpdatesAreVisible
, ownDeletesAreVisible , and ownInsertsAreVisible . These methods
are needed since this capability can vary between DBMSs and JDBC drivers.
One's own updates are visible if an updated column value can be retrieved by calling
The following example, shows how an application may determine whether a
DatabaseMetaData dmd; ... if (dmd. 5.8.4 Detecting changesTheResultSet.wasUpdated() , wasDeleted() , and wasInserted() methods can be
called to determine whether a row has been effected by a visible update, delete, or insert
respectively since the result set was opened. The ability of a result set to detect changes
is orthogonal to its ability to make changes visible. In other words, visible changes are
not automatically detected.
The
boolean bool = dmd.deletesAreDetected( ResultSet.TYPE_SCROLL_SENSITIVE);
If deletesAreDetected returns 5.9 Refetching a rowSome applications may need to see up-to-the-second changes that have been made to a row. Since a JDBC driver can do prefetching and caching of data that is read from the underlying database (seeResultSet.setFetchSize() ), an application may not see
the very latest changes that have been made to a row, even when a sensitive result set
is used and updates are visible. The ResultSet.refreshRow() method is provided to
allow an application to request that a driver refresh a row with the latest values stored
in the database. A JDBC driver may actually refresh multiple rows at once if the fetch
size is greater than one. Applications should exercise restraint in calling refreshRow() , since calling this method frequently will likely slow performance.
5.10 JDBC API complianceAlthough we expect most JDBC drivers to support scrollable result sets, we have made them optional to minimize the complexity of implementing JDBC drivers for data sources that do not support scrollability. The goal is that it be possible for a JDBC driver to implement scrollable result sets using the support provided by the underlying database system for systems that have such support. If the DBMS associated with a driver does not support scrollability then this feature may be omitted, or a JDBC driver may implement scrollability as a layer on top of the DBMS. Its important to note that JDBC technology rowsets, which are part of the JDBC Optional Package API, always support scrollability, so a rowset can be used when the underlying DBMS doesn't support scrollable results.
Contents | Prev | Next jdbc@eng.sun.com or jdbc-business@eng.sun.com Copyright © 1996-1999 Sun Microsystems, Inc. All rights reserved. |