CachedRowSetDataProvider and CachedRowSet Info
By jfbrown on Dec 15, 2005
The CachedRowSetDataProvider is a wrapper to data in a CachedRowSet. It's primary purpose is to facilitate binding to components.
The only piece of information the CachedRowSetDataProvider holds is a cursor position into the CachedRowSet. If multiple CachedRowSetDataProvider instances reference the same CachedRowSet, they can each have their own cursor position (caution: see the section below on threading). Again, all data from the database is stored in the CachedRowSet.
CachedRowSet Cursor Position
Many the CachedRowSetDataProvider methods may move the cursor position in the underlying CachedRowSet. The CachedRowSetDataProvider methods findFirst(), setCursorRow(), getValue(), setValue() and others may/will move the CachedRowSet's cursor.
Big Rule: if you rely on cursor postion in the CachedRowSet, access it only through CachedRowSet methods or only through CachedRowSetDataProvider methods. Any cursor movement through CachedRowSet methods will not be seen by a CachedRowSetDataProvider.
Closing your CachedRowSetDataProvider
If your CachedRowSet is in a "higher" scope, remember to call close() on your CachedRowSetDataProvider. For example, if your CachedRowSetDataProvider is in your page (request scope) and the CachedRowSet is in your session bean (session scope), call close(). This is the default for Creator, so you'll notice we add the call to close() the CachedRowSetDataProvider into the page's destroy() method.
Internally, the dataProvider adds a listener to the RowSet instance to detect changes so that listeners to the dataProvider can be notified of those changes. The method close() removes that listener.
Without the close() (i.e., removing the listener) the DataProvider instance cannot be garbage collected even though it's in request scope and should be gc'd after the response is rendered. Failure to close the CachedRowSetDataProvider in this situation will manifest itself as a slow memory leak.
CachedRowSetDataProvider.close() also move's the CachedRowSet's cursor to the first row.
The CachedRowSetDataProvider.close() does nothing else to the CachedRowSet: the CachedRowSet's data and properties are not changed.
What happens in a CachedRowSet.close()?
The row data is released and many properties are reset to default, such as showDeleted, queryTimeout, maxRows,
maxFieldSize, type, concurrency, readOnly, and transactionIsolation.
What happens in a CachedRowSet.release()?
The row data is released (see the javadoc for more details). Use release() if you intend to re-execute the query at a later time
What happens in a CachedRowSetDataProvider.refresh()?
This calls CachedRowSet.release() and resets the CachedRowSetDataProvider's cursor. It does not execute() the CachedRowSet at this time.
When is a CachedRowSet executed?
CachedRowSetDataProvider methods that would require an executed CachedRowSet will automagically execute it.
You can force execution by called CachedRowSet.execute().
CachedRowSet and Multiple Request Threads
Although multiple CachedRowSetDataProvider instances may use the same CachedRowSet (there's nothing to stop you) care should be taken that those CachedRowSetDataProvider instances do not access the CachedRowSet at the same time. Creator (and JSF) does nothing to help prevent simultaneous access.
The chances for problems are small, but they do exist.
Sample problem: Let's say each dataProvider calls setValue() on a different row. The dp.setValue() essentially does two steps: it moves the CachedRowSet cursor to the row and then calls setObject(). If the first thread yields after moving the cursor, the second dataProvider may sneak in and move the CachedRowSet cursor. This means the first thread would then call setObject() on the wrong row.
Multiple button clicks before a response is returned can generate multiple requests and thus multiple threads.