Description
This issue was brought up by a customer. I wanted to capture it in a GitHub issue in case others encounter it and need to know why the driver behaves the way it does.
Driver version
7.0.0
SQL Server version
SQL Server 2017
Client Operating System
Windows 10
JAVA/JVM version
JRE 10
Table schema
CREATE TABLE TestTable (TestColumn varchar(max));
create table testtable2 (testcolumn varchar(max))
declare @i int = 0
while @i < 10000
begin
insert into testtable2 (testcolumn) values
('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')
select @i = @i + 1
end
set @i = 0
while @i < 500
begin
insert into testtable (testcolumn) select testcolumn from testtable2
select @i = @i + 1
end
Problem description
Execute a SQL query that returns a large result set, but only read a few rows before doing connection.rollback()
- Expected behavior:
Rollback is executed, ResultSet is closed immediately (less than a second). - Actual behavior:
ResultSet.close() is causing all rows to be fetched from the server and taking a long time to close.
Reproduction code
System.out.println("Start " + new java.util.Date().toString());
String connectionString = "jdbc:sqlserver://<server>:1433;databaseName=<DBname>;user=<username>;password=<password>";
try (Connection conn = DriverManager.getConnection(connectionString)) {
conn.setAutoCommit(false);
try (Statement statement = conn.createStatement()) {
ResultSet rs = statement.executeQuery("select TestColumn from TestTable");
try {
while (rs.next()) {
System.out.println(rs.getString(1));
throw new SQLException("Testing...");
}
} finally {
System.out.println("Closing rs " + new java.util.Date().toString());
rs.close();
System.out.println("Rs closed " + new java.util.Date().toString());
}
} catch (SQLException se) {
se.printStackTrace();
conn.rollback();
System.out.println("Rollback complete " + new java.util.Date().toString());
}
} catch (SQLException e) {
e.printStackTrace();
}
System.out.println("Done " + new java.util.Date().toString());
Workaround
You can call statement.cancel() to abort processing of further results before calling rs.close(). This will have the effect of cancelling all result sets that might be following the first one being returned by the statement.
This behavior is by design and is not specific to the JDBC driver. All drivers that communicate with SQL Server must follow the TDS specification. A statement may return multiple result sets, whether it is multiple SELECT statements in a batch or a stored procedure which returns multiple result sets. Closing a result set tells the driver to move on to the next one and the only way to get to the next one is to fetch the stream of data until the next result set is encountered. There is no way to tell the server to skip ahead in the stream to the next result set. The server will not even begin producing/writing subsequent result sets to the stream until all previous rows are read.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status