What's the difference, behaviour-wise, between fetching results using server cursors and fetching using streaming?
The former (server cursors) can be activated:
For every statement by setting useCursorFetch=true
and defaultFetchSize=N
in the connection properties. (Where N is a number greater than zero.)
Or individual statements by initially setting useCursorFetch=true
or com.mysql.jdbc.Connection.setUseCursorFetch(true)
on the connection, followed by java.sql.Statement.setFetchSize(N)
on the statement.
The latter (streaming) can be activated:
On individual statements by setting java.sql.Statement.setFetchSize(Integer.MIN_VALUE)
or by calling com.mysql.jdbc.Statement.enableStreamingResults()
on the statment.
And probably on every statement by setting defaultFetchSize=X
in the connection properties, where X is a number equal to Integer.MIN_VALUE
.
What does one need to consider when developing with these alternative methods? A good answer may touch on topics such as performance, lock holding, and resource allocation (/ deallocation).
A server-side cursor enables a result set to be generated on the server side, but not transferred to the client except for those rows that the client requests. For example, if a client executes a query but is only interested in the first row, the remaining rows are not transferred.
viewTable , the first column in each row of the ResultSet rs is COF_NAME , which stores a value of SQL type VARCHAR . The method for retrieving a value of SQL type VARCHAR is getString . The second column in each row stores a value of SQL type INTEGER , and the method for retrieving values of that type is getInt .
For a full description of the SQL Server cursor types, see Type of Cursors. The JDBC specification provides support for forward-only and scrollable cursors that are sensitive or insensitive to changes made by other jobs, and can be read-only or updatable.
Examining Mysql's Connector/J source code (v5.1.39):
When using server cursor (setUseCursorFetch(true)
) and if the result set type is TYPE_FORWARD_ONLY
, it seems like the "streaming" mode is just a special case where the fetched block is 1-row only:
////// RowDataCursor.java /////////
private void fetchMoreRows() throws SQLException {
...
synchronized (this.owner.connection.getConnectionMutex()) {
...
int numRowsToFetch = this.owner.getFetchSize();
...
if (numRowsToFetch == Integer.MIN_VALUE) {
// Handle the case where the user used 'old' streaming result sets
numRowsToFetch = 1;
}
See also MysqlIO.java
for the conditions where RowDataCursor
is instantiated:
//
// Handle cursor-based fetch first
//
if (this.connection.versionMeetsMinimum(5, 0, 2) && this.connection.getUseCursorFetch() && isBinaryEncoded && callingStatement != null
&& callingStatement.getFetchSize() != 0 && callingStatement.getResultSetType() == ResultSet.TYPE_FORWARD_ONLY) {
ServerPreparedStatement prepStmt = (com.mysql.jdbc.ServerPreparedStatement) callingStatement;
boolean usingCursor = true;
MySQL 5.7 documentation indicates that using server cursor generates a temporary table at the server side (memory table if size allows) so this may affect server performance.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With