Standard Java Database Connectivity (JDBC) 2.0 features in Java Development Kit (JDK) 1.2.x include enhancements to result set functionality, such as processing forward or backward, positioning relatively or absolutely, seeing changes to the database made internally or externally, and updating result set data and then copying the changes to the database.
This chapter discusses these features, including the following topics:
This section provides an overview of JDBC 2.0 result set functionality and categories, and some discussion of implementation requirements for the Oracle JDBC drivers. This section covers the following topics:
Result Set Functionality and Result Set Categories Supported in JDBC 2.0
Oracle JDBC Implementation Overview for Result Set Enhancements
Result set functionality in JDBC 2.0 includes enhancements for scrollability and positioning, sensitivity to changes by others, and updatability.
Scrollability, positioning, and sensitivity are determined by the result set type.
Updatability is determined by the concurrency type.
Specify the desired result set type and concurrency type when you create the statement object that will produce the result set.
Together, the various result set types and concurrency types provide for six different categories of result set.
Scrollability, Positioning, and Sensitivity
Scrollability refers to the ability to move backward as well as forward through a result set. Associated with scrollability is the ability to move to any particular position in the result set, through either relative positioning or absolute positioning.
Relative positioning enables you to move a specified number of rows forward or backward from the current row. Absolute positioning enables you to move to a specified row number, counting from either the beginning or the end of the result set.
Under JDBC 2.0, scrollable/positionable result sets are also available.
When creating a scrollable/positionable result set, you must also specify sensitivity. This refers to the ability of a result set to detect and reveal changes made to the underlying database from outside the result set.
A sensitive result set can see changes made to the database while the result set is open, providing a dynamic view of the underlying data. Changes made to the underlying columns values of rows in the result set are visible.
An insensitive result set is not sensitive to changes made to the database while the result set is open, providing a static view of the underlying data. You would need to retrieve a new result set to see changes made to the database.
Result Set Types for Scrollability and Sensitivity
When you create a result set under JDBC 2.0 functionality, you must choose a particular result set type to specify whether the result set is scrollable/positional and sensitive to underlying database changes.
If the JDBC 1.0 functionality is all you desire, JDBC 2.0 continues to support this through the forward-only result set type. A forward-only result set cannot be sensitive.
If you want a scrollable result set, then you must also specify sensitivity. Specify the scroll-sensitive type for the result set to be scrollable and sensitive to underlying changes. Specify the scroll-insensitive type for the result set to be scrollable but not sensitive to underlying changes.
To summarize, the following result set types are available with JDBC 2.0:
This is a JDBC 1.0 functionality. This type of result set is not scrollable, not positionable, and not sensitive.
This type of result set is scrollable and positionable. It is also sensitive to underlying database changes.
This type of result set is scrollable and positionable, but not sensitive to underlying database changes.
Note:
The sensitivity of a scroll-sensitive result set is affected by fetch size.Updatability refers to the ability to update data in a result set and then copy the changes to the database. This includes inserting new rows into the result set or deleting existing rows.
Updatability might also require database write locks to mediate access to the underlying database. Because you cannot have multiple write locks concurrently, updatability in a result set is associated with concurrency in database access.
Result sets can optionally be updatable under JDBC 2.0
Note:
Updatability is independent of scrollability and sensitivity. Although, it is typical for an updatable result set to also be scrollable so that you can position it to particular rows that you want to update or delete.Concurrency Types for Updatability
The concurrency type of a result set determines whether it is updatable. Under JDBC 2.0, the following concurrency types are available:
In this case, updates, inserts, and deletes can be performed on the result set and copied to the database.
The result set cannot be modified in any way.
Summary of Result Set Categories
Because scrollability and sensitivity are independent of updatability, the three result set types and two concurrency types combine for a total of six result set categories, as follows:
forward-only/read-only
forward-only/updatable
scroll-sensitive/read-only
scroll-sensitive/updatable
scroll-insensitive/read-only
scroll-insensitive/updatable
Note:
A forward-only updatable result set has no positioning functionality. You can only update rows as you iterate through them with thenext
method.This section discusses key aspects of the Oracle JDBC implementation of result set enhancements for scrollability, through use of a client-side cache, and for updatability, through use of ROWID
s.
It is permissible for customers to implement their own client-side caching mechanism, and Oracle provides an interface to use in doing so.
Oracle JDBC Implementation for Result Set Scrollability
Because the underlying server does not support scrollable cursors, Oracle JDBC must implement scrollability in a separate layer.
It is important to be aware that this is accomplished by using a client-side memory cache to store rows of a scrollable result set.
Important:
Because all rows of any scrollable result set are stored in the client-side cache, a situation where the result set contains many rows, many columns, or very large columns might cause the client-side Java virtual machine (JVM) to fail. Do not specify scrollability for a large result set.Oracle JDBC Implementation for Result Set Updatability
To support updatability, Oracle JDBC uses ROWID
to uniquely identify database rows that appear in a result set. For every query into an updatable result set, the Oracle JDBC driver automatically retrieves the ROWID
along with the columns you select.
Note:
Client-side caching is not required by updatability in and of itself. In particular, a forward-only updatable result set will not require a client-side cache.Implementing a Custom Client-Side Cache for Scrollability
There is some flexibility in how to implement client-side caching in support of JDBC 2.0 scrollable result sets.
Although Oracle JDBC provides a complete implementation, it also supplies an interface, OracleResultSetCache
, that you can implement as desired:
public interface OracleResultSetCache { /** * Save the data in the i-th row and j-th column. */ public void put (int i, int j, Object value) throws IOException; /** * Return the data stored in the i-th row and j-th column. */ public Object get (int i, int j) throws IOException; /** * Remove the i-th row. */ public void remove (int i) throws IOException; /** * Remove the data stored in i-th row and j-th column */ public void remove (int i, int j) throws IOException; /** * Remove all data from the cache. */ public void clear () throws IOException; /** * Close the cache. */ public void close () throws IOException; }
If you implement this interface with your own class, then your application code must instantiate your class and then use the setResultSetCache
method of an OracleStatement
, OraclePreparedStatement
, or OracleCallableStatement
object to set the caching mechanism to use your implementation. Following is the method signature:
void setResultSetCache(OracleResultSetCache cache) throws SQLException
Call this method prior to running a query. The result set produced by the query will then use your specified caching mechanism.
In using JDBC 2.0 result set enhancements, you may specify the result set type and the concurrency type when you create a generic statement or prepare a prepared statement or callable statement that will run a query.
This section discusses the creation of result sets to use JDBC 2.0 enhancements. It covers the following topics:
Under JDBC 2.0, the Connection
class has the following methods that take a result set type and a concurrency type as input:
Statement createStatement(int resultSetType, int resultSetConcurrency)
PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency)
CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency)
The statement objects created will have the intelligence to produce the appropriate kind of result sets.
You can specify one of the following static
constant values for result set type:
ResultSet.TYPE_FORWARD_ONLY
ResultSet.TYPE_SCROLL_INSENSITIVE
ResultSet.TYPE_SCROLL_SENSITIVE
And you can specify one of the following static
constant values for concurrency type:
ResultSet.CONCUR_READ_ONLY
ResultSet.CONCUR_UPDATABLE
After creating a Statement
, PreparedStatement
, or CallableStatement
object, you can verify its result set type and concurrency type by calling the following methods on the statement object:
int getResultSetType() throws SQLException
int getResultSetConcurrency() throws SQLException
Example 19-1 Prepared Statement Object With Result Set
Following is an example of a prepared statement object that specifies a scroll-sensitive and updatable result set for queries run through that statement:
... PreparedStatement pstmt = conn.prepareStatement ("SELECT empno, sal FROM emp WHERE empno = ?", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); pstmt.setString(1, "28959"); ResultSet rs = pstmt.executeQuery(); ...
Some types of result sets are not feasible for certain kinds of queries. If you specify an unfeasible result set type or concurrency type for the query you run, then the JDBC driver follows a set of rules to determine the best feasible types to use instead.
The actual result set type and concurrency type are determined when the statement is run, with the driver issuing a SQLWarning
on the statement object if the desired result set type or concurrency type is not feasible. The SQLWarning
object will contain the reason why the requested type was not feasible. Check for warnings to verify whether you received the type of result set that you requested.
The following limitations are placed on queries for enhanced result sets. Failure to follow these guidelines will result in the JDBC driver choosing an alternative result set type or concurrency type.
To produce an updatable result set:
A query can select from only a single table and cannot contain any join operations.
In addition, for inserts to be feasible, the query must select all non-nullable columns and all columns that do not have a default value.
A query cannot use SELECT *
.
However, there is a workaround for this.
A query must select table columns only.
It cannot select derived columns or aggregates, such as the SUM
or MAX
of a set of columns.
To produce a scroll-sensitive result set:
A query cannot use SELECT *
.
However, there is a workaround for this.
A query can select from only a single table.
Scrollable and updatable result sets cannot have any column as Stream
. When the server has to fetch a Stream
column, it reduces the fetch size to one and blocks all columns following the Stream
column until the Stream
column is read. As a result, columns cannot be fetched in bulk and scrolled through.
As a workaround for the SELECT *
limitation, you can use table aliases, as shown in the following example:
SELECT t.* FROM TABLE t ...
Note:
There is a simple way to determine if your query will probably produce a scroll-sensitive or updatable result set: If you can legally add aROWID
column to the query list, then the query is probably suitable for either a scroll-sensitive or an updatable result set.If the specified result set type or concurrency type is not feasible, then the Oracle JDBC driver uses the following rules in choosing alternate types:
If the specified result set type is TYPE_SCROLL_SENSITIVE
, but the JDBC driver cannot fulfill that request, then the driver attempts a downgrade to TYPE_SCROLL_INSENSITIVE
.
If the specified or downgraded result set type is TYPE_SCROLL_INSENSITIVE
, but the JDBC driver cannot fulfill that request, then the driver attempts a downgrade to TYPE_FORWARD_ONLY
.
If the specified concurrency type is CONCUR_UPDATABLE
, but the JDBC driver cannot fulfill that request, then the JDBC driver attempts a downgrade to CONCUR_READ_ONLY
.
Notes:
Any manipulations of the result set type and concurrency type by the JDBC driver are independent of each other.Verifying Result Set Type and Concurrency Type
After a query has been run, you can verify the result set type and concurrency type that the JDBC driver actually used, by calling methods on the result set object.
int getType() throws SQLException
This method returns an int
value for the result set type used for the query. ResultSet.TYPE_FORWARD_ONLY
, ResultSet.TYPE_SCROLL_SENSITIVE
, or ResultSet.TYPE_SCROLL_INSENSITIVE
are the possible values.
int getConcurrency() throws SQLException
This method returns an int
value for the concurrency type used for the query. ResultSet.CONCUR_READ_ONLY
or ResultSet.CONCUR_UPDATABLE
are the possible values.
Scrollable result sets enable you to iterate through them, either forward or backward, and to position the result set to any desired row.
This section discusses positioning within a scrollable result set and how to process a scrollable result set backward, instead of forward. It covers the following sections:
In a scrollable result set, you can use several result set methods to move to a desired position and to check the current position.
Note:
You cannot position a forward-only result set. Any attempt to position it or to determine the current position will result in aSQLException
.Methods for Moving to a New Position
The following result set methods are available for moving to a new position in a scrollable result set:
void beforeFirst() throws SQLException
Positions to before the first row of the result set, or has no effect if there are no rows in the result set. This is where you would typically start iterating through a result set to process it going forward and is the default initial position for any kind of result set.
You are outside the result set bounds after a beforeFirst()
call. There is no valid current row, and you cannot position relatively from this point.
void afterLast() throws SQLException
Positions to after the last row of the result set, or has no effect if there are no rows in the result set. This is where you would typically start iterating through a result set to process it going backward.
You are outside the result set bounds after an afterLast()
call. There is no valid current row, and you cannot position relatively from this point.
boolean first() throws SQLException
Positions to the first row of the result set, or returns false
if there are no rows in the result set.
boolean last() throws SQLException
Positions to the last row of the result set, or returns false
if there are no rows in the result set.
boolean absolute(int row) throws SQLException
Positions to an absolute row from either the beginning or end of the result set. If you input a positive number, then it positions from the beginning. If you input a negative number, then it positions from the end. This method returns false
if there are no rows in the result set.
Attempting to move forward beyond the last row, such as an absolute(11)
call if there are 10 rows, will position to after the last row, having the same effect as an afterLast()
call.
Attempting to move backward beyond the first row, such as an absolute(-11)
call if there are 10 rows, will position to before the first row, having the same effect as a beforeFirst()
call.
Note:
Callingabsolute(1)
is equivalent to calling first()
; calling absolute(-1)
is equivalent to calling last()
.boolean relative(int row) throws SQLException
Moves to a position relative to the current row, forward if you input a positive number or backward if you input a negative number, or returns false
if there are no rows in the result set.
The result set must be at a valid current row for use of the relative
method.
Attempting to move forward beyond the last row will position to after the last row, having the same effect as an afterLast()
call.
Attempting to move backward beyond the first row will position to before the first row, having the same effect as a beforeFirst()
call.
A relative(0)
call is valid but has no effect.
Note:
You cannot position relatively from before the first row, which is the default initial position, or after the last row. Attempting relative positioning from either of these positions would result in aSQLException
.Methods for Checking the Current Position
The following result set methods are available for checking the current position in a scrollable result set:
boolean isBeforeFirst() throws SQLException
Returns true
if the position is before the first row.
boolean isAfterLast() throws SQLException
Returns true
if the position is after the last row.
boolean isFirst() throws SQLException
Returns true
if the position is at the first row.
boolean isLast() throws SQLException
Returns true
if the position is at the last row.
int getRow() throws SQLException
Returns the row number of the current row, or returns 0 if there is no valid current row.
Note:
Theboolean
methods, isFirst()
, isLast()
, isAfterFirst()
, and isAfterLast()
, all return false
. Also, they do not throw an exception if there are no rows in the result set.In a scrollable result set you can iterate backward instead of forward as you process the result set. The following methods are available:
The previous()
method works similarly to the next()
method, in that it returns true
as long as the new current row is valid, and false
as soon as it runs out of rows, that is, has passed the first row.
Backward versus Forward Processing
You can process the entire result set going forward, using the next()
method. The default initial position in the result set is before the first row, appropriately, but you can call the beforeFirst()
method if you have moved elsewhere since the result set was created.
To process the entire result set going backward, call afterLast()
, then use the previous()
method. For example:
... /* NOTE: The specified concurrency type, CONCUR_UPDATABLE, is not relevant to this example. */ Statement stmt = conn.createStatement (ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs = stmt.executeQuery("SELECT empno, sal FROM emp"); rs.afterLast(); while (rs.previous()) { System.out.println(rs.getString("empno") + " " + rs.getFloat("sal")); } ...
Unlike relative positioning, you can use next()
from before the first row and previous()
from after the last row. You do not have to be at a valid current row to use these methods.
Note:
In a non-scrollable result set, you can process only with thenext()
method. Attempting to use the previous()
method will cause a SQLException
.Presetting the Fetch Direction
The JDBC 2.0 standard allows the ability to pre-specify the direction, known as the fetch direction, for use in processing a result set. This allows the JDBC driver to optimize its processing. The following result set methods are specified:
void setFetchDirection(int direction) throws SQLException
int getFetchDirection() throws SQLException
The Oracle JDBC drivers support only the forward preset value, which you can specify by inputting the ResultSet.FETCH_FORWARD
static constant value.
The values ResultSet.FETCH_REVERSE
and ResultSet.FETCH_UNKNOWN
are not supported. Attempting to specify them causes a SQL warning, and the settings are ignored.
A concurrency type of CONCUR_UPDATABLE
enables you to update rows in the result set, delete rows from the result set, or insert rows into the result set.
After you perform an UPDATE
or INSERT
operation in a result set, you propagate the changes to the database in a separate step that you can skip if you want to cancel the changes.
However, a DELETE
operation in a result set is immediately run, but not necessarily committed, in the database as well.
Note:
When using an updatable result set, it is typical to also make it scrollable. This enables you to position to any row that you want to change. With a forward-only updatable result set, you can change rows only as you iterate through them with thenext()
method.This section covers the following topics:
The result set deleteRow()
method will delete the current row. Following is the method signature:
void deleteRow() throws SQLException
Note:
UnlikeUPDATE
and INSERT
operations in a result set, which require a separate step to propagate the changes to the database, a DELETE
operation in a result set is immediately run in the corresponding row in the database as well.
Once you call deleteRow()
, the changes will be made permanent with the next transaction COMMIT
operation. Remember also that by default, the auto-commit flag is set to true
. Therefore, unless you override this default, any deleteRow()
operation will be run and committed immediately.
Presuming the result set is also scrollable, you can position to a row using any of the available positioning methods, except beforeFirst()
and afterLast()
, which do not go to a valid current row, and then delete that row, as in the following example:
... rs.absolute(5); rs.deleteRow(); ...
Important:
The deleted row remains in the result set object even after it has been deleted from the database.In a scrollable result set, by contrast, a DELETE
operation is evident in the local result set object. The row would no longer be in the result set after the DELETE
. The row preceding the deleted row becomes the current row, and row numbers of subsequent rows are changed accordingly.
Performing a result set UPDATE
operation requires two separate steps to first update the data in the result set and then copy the changes to the database.
Presuming the result set is also scrollable, you can position to a row using any of the available positioning methods, except beforeFirst()
and afterLast()
, which do not go to a valid current row, and then update that row as desired.
Here are the steps for updating a row in the result set and database:
Call the appropriate update
XXX
methods to update the data in the columns you want to change.
With JDBC 2.0, a result set object has an update
XXX
method for each data type, as with the set
XXX
methods previously available for updating the database directly.
Each of these methods takes an int
for the column number or a string for the column name and then an item of the appropriate data type to set the new value. Following are a couple of examples for a result set rs
:
rs.updateString(1, "mystring"); rs.updateFloat(2, 10000.0f);
Call the updateRow
method to copy the changes to the database or the cancelRowUpdates
method to cancel the changes.
Once you call updateRow
, the changes are run and will be made permanent with the next transaction COMMIT
operation. Be aware that by default, the auto-commit flag is set to true
so that any operation run is committed immediately.
If you choose to cancel the changes before copying them to the database, then call the cancelRowUpdates
method instead. This will also revert to the original values for that row in the local result set object. Note that once you call the updateRow
method, the changes are written to the transaction and cannot be canceled unless you roll back the transaction.
Note:
Auto-commit must be disabled to allow aROLLBACK
operation.Positioning to a different row before calling updateRow
also cancels the changes and reverts to the original values in the result set.
Before calling updateRow
, you can call the usual get
XXX
methods to verify that the values have been updated correctly. These methods take an int
column index or string column name as input. For example:
float myfloat = rs.getFloat(2);
...
// process myfloat to see if it's appropriate
...
Note:
Result setUPDATE
operations are visible in the local result set object for all result set types, forward-only, scroll-sensitive, and scroll-insensitive.Following is an example of a result set UPDATE
operation that is also copied to the database. The tenth row is updated. The column number is used to specify column 1, and the column name, sal
, is used to specify column 2.
Statement stmt = conn.createStatement (ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs = stmt.executeQuery("SELECT empno, sal FROM emp"); if (rs.absolute(10)) // (returns false if row does not exist) { rs.updateString(1, "28959"); rs.updateFloat("sal", 100000.0f); rs.updateRow(); } // Changes are made permanent with the next COMMIT operation.
Result set INSERT
operations use what is called the result set insert-row, which is a staging area that holds the data for the inserted row until it is copied to the database. You must explicitly move to this row to write the data that will be inserted.
As with UPDATE
operations, result set INSERT
operations require separate steps to first write the data to the insert-row and then copy it to the database.
Following are the steps in running a result set INSERT
operation.
Move to the insert-row by calling the result set moveToInsertRow
method.
As with UPDATE
operations, use the appropriate update
XXX
methods to write data to the columns. For example:
rs.updateString(1, "mystring"); rs.updateFloat(2, 10000.0f);
You can specify a string for column name, instead of an integer for column number.
Important:
Each column value in the insert-row is undefined until you call theupdate
XXX
method for that column. You must call this method and specify a non-null value for all non-nullable columns, or else attempting to copy the row into the database will result in a SQLException
.
However, it is permissible to not call update
XXX
for a nullable column. This will result in a value of null
.
Copy the changes to the database by calling the result set insertRow
method.
Once you call insertRow
, the insert is processed and will be made permanent with the next transaction COMMIT
operation.
Positioning to a different row before calling insertRow
cancels the insert and clears the insert-row.
Before calling insertRow
you can call the usual get
XXX
methods to verify that the values have been set correctly in the insert-row. These methods take an int
column index or string column name as input. For example:
float myfloat = rs.getFloat(2);
...process myfloat to see if it's appropriate...
Note:
No result set type can see a row inserted by a result setINSERT
operation.The following example performs a result set INSERT
operation, moving to the insert-row, writing the data, copying the data into the database, and then returning to what was the current row prior to going to the insert-row. The column number is used to specify column 1, and the column name, sal
, is used to specify column 2.
... Statement stmt = conn.createStatement (ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs = stmt.executeQuery("SELECT empno, sal FROM emp"); rs.moveToInsertRow(); rs.updateString(1, "28959"); rs.updateFloat("sal", 100000.0f); rs.insertRow(); // Changes will be made permanent with the next COMMIT operation. rs.moveToCurrentRow(); // Go back to where we came from... ...
It is important to be aware of the following facts regarding updatable result sets with the JDBC drivers:
The drivers do not enforce write locks for an updatable result set.
The drivers do not check for conflicts with a result set DELETE
or UPDATE
operation.
A conflict will occur if you try to perform a DELETE
or UPDATE
operation on a row updated by another committed transaction.
The Oracle JDBC drivers use the ROWID
to uniquely identify a row in a database table. As long as the ROWID
is valid when a driver tries to send an UPDATE
or DELETE
operation to the database, the operation will be run.
The driver will not report any changes made by another committed transaction. Any conflicts are silently ignored and your changes will overwrite the previous changes.
To avoid such conflicts, use the Oracle FOR UPDATE
feature when running the query that produces the result set. This will avoid conflicts, but will also prevent simultaneous access to the data. Only a single write lock can be held concurrently on a data item.
By default, when Oracle JDBC runs a query, it retrieves a result set of 10 rows at a time from the database cursor. This is the default Oracle row-prefetch value. You can change the number of rows retrieved with each trip to the database cursor by changing the row-prefetch value.
JDBC 2.0 also enables you to specify the number of rows fetched with each database round trip for a query, and this number is referred to as the fetch size. In Oracle JDBC, the row-prefetch value is used as the default fetch size in a statement object. Setting the fetch size overrides the row-prefetch setting and affects subsequent queries run through that statement object.
Fetch size is also used in a result set. When the statement object run a query, the fetch size of the statement object is passed to the result set object produced by the query. However, you can also set the fetch size in the result set object to override the statement fetch size that was passed to it.
Note:
Changes made to the fetch size of a statement object after a result set is produced will have no affect on that result set.The result set fetch size, either set explicitly, or by default equal to the statement fetch size that was passed to it, determines the number of rows that are retrieved in any subsequent trips to the database for that result set. This includes any trips that are still required to complete the original query, as well as any refetching of data into the result set. Data can be refetched, either explicitly or implicitly, to update a scroll-sensitive or scroll-insensitive/updatable result set.
This section covers the following topics:
The following methods are available in all Statement
, PreparedStatement
, CallableStatement
, and ResultSet
objects for setting and getting the fetch size:
To set the fetch size for a query, call setFetchSize
on the statement object prior to running the query. If you set the fetch size to N, then N rows are fetched with each trip to the database.
After you have run the query, you can call setFetchSize
on the result set object to override the statement object fetch size that was passed to it. This will affect any subsequent trips to the database to get more rows for the original query, as well as affecting any later refetching of rows.
Using the JDBC 2.0 fetch size is fundamentally similar to using the Oracle row-prefetch value, except that with the row-prefetch value you do not have the flexibility of distinct values in the statement object and result set object. The row prefetch value would be used everywhere.
Furthermore, JDBC 2.0 fetch size usage is portable and can be used with other JDBC drivers. Oracle row-prefetch usage is vendor-specific.
See Also:
"Oracle Row Prefetching"Note:
Do not mix the JDBC 2.0 fetch size application programming interface (API) and the Oracle row prefetching API in your application. You can use one or the other, but not both.The result set refreshRow
method is supported for some types of result sets for refetching data. This consists of going back to the database to re-obtain the database rows that correspond to n rows in the result set, starting with the current row, where n is the fetch size. This lets you see the latest updates to the database that were made outside of your result set, subject to the isolation level of the enclosing transaction.
Because refetching re-obtains only rows that correspond to rows already in your result set, it does nothing about rows that have been inserted or deleted in the database since the original query. It ignores rows that have been inserted, and rows will remain in your result set even after the corresponding rows have been deleted from the database. When there is an attempt to refetch a row that has been deleted in the database, the corresponding row in the result set will maintain its original values.
Following is the signature of the refreshRow
method:
void refreshRow() throws SQLException
You must be at a valid current row when you call this method, not outside the row bounds and not at the insert-row.
The refreshRow
method is supported for the following result set categories:
scroll-sensitive/read-only
scroll-sensitive/updatable
scroll-insensitive/updatable
Note:
Scroll-sensitive result set functionality is implemented through implicit calls torefreshRow
.This section discusses the ability of a result set to see the following:
Changes made from elsewhere, either from your own transaction outside the result set, or from other committed transactions, referred to as external changes
Note:
External changes are referred to as other's changes in the Sun Microsystems JDBC 2.0 specification.This section covers the following topics:
The ability of an updatable result set to see its own changes depends on both the result set type and the kind of change. This is summarized as follows:
Internal DELETE
operations are visible for scrollable result sets, but are not visible for forward-only result sets.
After you delete a row in a scrollable result set, the preceding row becomes the new current row, and subsequent row numbers are updated accordingly.
Internal UPDATE
operations are always visible, regardless of the result set type.
Internal INSERT
operations are never visible, regardless of the result set type.
An internal change being visible essentially means that a subsequent get
XXX
call will see the data changed by a preceding update
XXX
call on the same data item.
JDBC 2.0 DatabaseMetaData
objects include the following methods to verify this:
Each takes a result set type, ResultSet.TYPE_FORWARD_ONLY
, ResultSet.TYPE_SCROLL_SENSITIVE
, or ResultSet.TYPE_SCROLL_INSENSITIVE
, as input.
Note:
When you make an internal change that causes a trigger to run, the trigger changes are effectively external changes. However, if the trigger affects data in the row you are updating, then you will see those changes for any scrollable/updatable result set, because an implicit row refetch occurs after the update.Only a scroll-sensitive result set can see external changes to the underlying database, and it can only see the changes from external UPDATE
operations. Changes from external DELETE or INSERT
operations are never visible.
Note:
Any discussion of seeing changes from outside the enclosing transaction presumes the transaction itself has an isolation level setting that allows the changes to be visible.JDBC 2.0 DatabaseMetaData
objects include the following methods to verify this:
Each takes a result set type, ResultSet.TYPE_FORWARD_ONLY
, ResultSet.TYPE_SCROLL_SENSITIVE
, or ResultSet.TYPE_SCROLL_INSENSITIVE
, as input.
Note:
Explicit use of therefreshRow
method is distinct from this discussion of visibility. For example, even though external updates are invisible to a scroll-insensitive result set, you can explicitly refetch rows in a scroll-insensitive/updatable result set and retrieve external changes that have been made. Visibility refers only to the fact that the scroll-insensitive/updatable result set would not see such changes automatically and implicitly.Regarding changes made to the underlying database by external sources, there are two similar but distinct concepts with respect to visibility of the changes from your local result set:
Visibility of changes
Detection of changes
A change being "visible" means that when you look at a row in the result set, you can see new data values from changes made by external sources to the corresponding row in the database.
A change being "detected", however, means that the result set is aware that this is a new value since the result set was first populated.
Even when an Oracle result set sees new data, as with an external UPDATE
in a scroll-sensitive result set, it has no awareness that this data has changed since the result set was populated. Such changes are not detected.
JDBC 2.0 DatabaseMetaData
objects include the following methods to verify this:
Each takes a result set type, ResultSet.TYPE_FORWARD_ONLY
, ResultSet.TYPE_SCROLL_SENSITIVE
, or ResultSet.TYPE_SCROLL_INSENSITIVE
, as input.
It follows, then, that result set methods specified by JDBC 2.0 to detect changes, rowDeleted
, rowUpdated
, and rowInserted
, will always return false
. There is no use in calling them.
Table 19-1 summarizes the discussion in the preceding sections regarding whether a result set object in the Oracle JDBC implementation can see changes made internally through the result set itself, and changes made externally to the underlying database from elsewhere in your transaction or from other committed transactions.
Table 19-1 Visibility of Internal and External Changes for Oracle JDBC
Result Set Type | Can See Internal DELETE? | Can See Internal UPDATE? | Can See Internal INSERT? | Can See External DELETE? | Can See External UPDATE? | Can See External INSERT? |
---|---|---|---|---|---|---|
forward-only |
no |
yes |
no |
no |
no |
no |
scroll-sensitive |
yes |
yes |
no |
no |
yes |
no |
scroll-insensitive |
yes |
yes |
no |
no |
no |
no |
Notes:
Remember that explicit use of the refreshRow
method, is distinct from the concept of visibility of external changes.
Remember that even when external changes are visible, as with UPDATE
operations underlying a scroll-sensitive result set, they are not detected. The result set rowDeleted
, rowUpdated
, and rowInserted
methods always return false
.
The Oracle implementation of scroll-sensitive result sets involves the concept of a window, with a window size that is based on the fetch size. The window size affects how often rows are updated in the result set.
Once you establish a current row by moving to a specified row, the window consists of the n rows in the result set starting with that row, where n is the fetch size being used by the result set. Note that there is no current row, and therefore no window, when a result set is first created. The default position is before the first row, which is not a valid current row.
As you move from row to row, the window remains unchanged as long as the current row stays within that window. However, once you move to a new current row outside the window, you redefine the window to be the N rows starting with the new current row.
Whenever the window is redefined, the N rows in the database corresponding to the rows in the new window are automatically refetched through an implicit call to the refreshRow
method, thereby updating the data throughout the new window.
So external updates are not instantaneously visible in a scroll-sensitive result set. They are only visible after the automatic refetches just described.
Note:
Because this kind of refetching is not a highly efficient or optimized methodology, there are significant performance concerns. Consider carefully before using scroll-sensitive result sets as currently implemented. There is also a significant trade-off between sensitivity and performance. The most sensitive result set is one with a fetch size of 1, which would result in the new current row being refetched every time you move between rows. However, this would have a significant impact on the performance of your application.This section summarizes all the new connection, result set, statement, and database meta data methods added for JDBC 2.0 result set enhancements. This section covers the following methods:
Following is an alphabetic summary of modified connection methods that allow you to specify result set and concurrency types when you create statement objects:
Statement createStatement(int resultSetType, int resultSetConcurrency)
This method enables you to specify result set type and concurrency type when you create a generic Statement
object.
CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency)
This method enables you to specify result set type and concurrency type when you create a PreparedStatement
object.
PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency)
This method enables you to specify result set type and concurrency type when you create a CallableStatement
object.
Following is an alphabetic summary of new result set methods for JDBC 2.0 result set enhancements:
boolean absolute(int row) throws SQLException
Move to an absolute row position in the result set.
void afterLast() throws SQLException
Move to after the last row in the result set.
void beforeFirst() throws SQLException
Move to before the first row in the result set.
void cancelRowUpdates() throws SQLException
Cancel an UPDATE
operation on the current row. Call this after the update
XXX
calls but before the updateRow
call.
void deleteRow() throws SQLException
Delete the current row.
boolean first() throws SQLException
Move to the first row in the result set.
int getConcurrency() throws SQLException
Returns an int
value for the concurrency type used for the query.
int getFetchSize() throws SQLException
Check the fetch size to determine how many rows are fetched in each database round trip.
int getRow() throws SQLException
Returns the row number of the current row. Returns 0 if there is no valid current row.
int getType() throws SQLException
Returns an int
value for the result set type used for the query.
void insertRow() throws SQLException
Write a result set INSERT
operation to the database. Call this after calling update
XXX
()
methods to set the data values.
boolean isAfterLast() throws SQLException
Returns true
if the position is after the last row.
boolean isBeforeFirst() throws SQLException
Returns true
if the position is before the first row.
boolean isFirst() throws SQLException
Returns true
if the position is at the first row.
boolean isLast() throws SQLException
Returns true
if the position is at the last row.
boolean last() throws SQLException
Move to the last row in the result set.
void moveToCurrentRow() throws SQLException
Move from the insert-row staging area back to what had been the current row prior to the moveToInsertRow()
call.
void moveToInsertRow() throws SQLException
Move to the insert-row staging area to set up a row to be inserted.
boolean next() throws SQLException
Iterate forward through the result set.
boolean previous() throws SQLException
Iterate backward through the result set.
void refreshRow() throws SQLException
Refetch the database rows corresponding to the current window in the result set, to update the data. This method is called implicitly for scroll-sensitive result sets.
boolean relative(int row) throws SQLException
Move to a relative row position, either forward or backward from the current row.
void setFetchSize(int rows) throws SQLException
Set the fetch size to determine how many rows are fetched in each database round trip when refetching.
void updateRow() throws SQLException
Write an UPDATE
operation to the database after using update
XXX
()
methods to update the data values.
void update
XXX
() throws SQLException
Set or update data values in a row to be updated or inserted. There is an update
XXX
method for each data type. After calling all the appropriate update
XXX
methods for the columns to be updated or inserted, call updateRow
for an UPDATE
operation or insertRow
for an INSERT
operation.
Following is an alphabetical summary of statement methods for JDBC 2.0 result set enhancements. These methods are available in generic statement, prepared statement, and callable statement objects.
int getFetchSize() throws SQLException
Check the fetch size to determine how many rows are fetched in each database round trip when executing a query.
void setFetchSize(int rows) throws SQLException
Set the fetch size to determine how many rows are fetched in each database round trip when executing a query.
void setResultSetCache(OracleResultSetCache cache) throws SQLException
Use your own client-side cache implementation for scrollable result sets. Create your own class that implements the OracleResultSetCache
interface, then use the setResultSetCache
method to input an instance of this class to the statement object that will create the result set.
int getResultSetType() throws SQLException
Check the result set type of result sets produced by this statement object, which was specified when the statement object was created.
int getResultSetConcurrency() throws SQLException
Check the concurrency type of result sets produced by this statement object, which was specified when the statement object was created.
Following is an alphabetical summary of database meta data methods for JDBC 2.0 result set enhancements.
boolean ownDeletesAreVisible(int) throws SQLException
Returns true
if, in this JDBC implementation, the specified result set type can see the effect of its own internal DELETE
operations.
boolean ownUpdatesAreVisible(int) throws SQLException
Returns true
if, in this JDBC implementation, the specified result set type can see the effect of its own internal UPDATE
operations.
boolean ownInsertsAreVisible(int) throws SQLException
Returns true
if, in this JDBC implementation, the specified result set type can see the effect of its own internal INSERT
operations.
boolean othersDeletesAreVisible(int) throws SQLException
Returns true
if, in this JDBC implementation, the specified result set type can see the effect of an external DELETE
operation in the database.
boolean othersUpdatesAreVisible(int) throws SQLException
Returns true
if, in this JDBC implementation, the specified result set type can see the effect of an external UPDATE
operation in the database.
boolean othersInsertsAreVisible(int) throws SQLException
Returns true
if, in this JDBC implementation, the specified result set type can see the effect of an external INSERT
operation in the database.
boolean deletesAreDetected(int) throws SQLException
Returns true
if, in this JDBC implementation, the specified result set type can detect when an external DELETE
operation occurs in the database. This method always returns false
.
boolean updatesAreDetected(int) throws SQLException
Returns true
if, in this JDBC implementation, the specified result set type can detect when an external UPDATE
operation occurs in the database. This method always returns false
.
boolean insertsAreDetected(int) throws SQLException
Returns true
if, in this JDBC implementation, the specified result set type can detect when an external INSERT
operation occurs in the database. This method always returns false
.