同事使用kettle迁移MySQL数据时出现了 SQLException,详细报错信息以下:html
Error reading from database: java.sql.SQLException: Streaming result set com.mysql.jdbc.RowDataDynamic@xxxxxxx is still active. No statements may be issued when any streaming result sets are open and in use on a given connection. Ensure that you have called .close() on any active streaming result sets before attempting more queries.
经查询MySQL官方文档(MySQL版本 5.1-8.0 同样),发现报错缘由是JDBC没有处理完resultSet结果集时又使用同一个connection提交了新的query。下面是官方文档对ResultSet的JDBC实现说明:java
默认状况下,ResultSet会一次性返回结果集并保存在内存中。这也是最有效率且最容易实现的一种方式。可是当ResultSet含有大量数据(不少行、或者包含大对象的状况下)时,JVM可能没法分配ResultSet要求的内存,这时你可让driver每次返回(stream)一行数据。mysql
要开启这个功能,须要以以下的方式来建立Statement:sql
stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY); stmt.setFetchSize(Integer.MIN_VALUE);
注意上面的statement建立语句,使用了 TYPE_FORWARD_ONLY、CONCUR_READ_ONLY,并将fetchSize设置为 Integer.MIN_VALUE。这种设置告诉driver须要逐行处理 result set。数据库
这种方式也有风险。在使用同一个 connection 来发起新的查询以前,你必须:1)读取 result set中的所有数据;2)或者将其关闭。不然就会抛出咱们前面所说的异常。并发
下面来讲说事务。此 Statement 持有的锁最快也要在statement 结束时才能释放。这里的锁包括了 MyISAM的表级锁或者InnoDB的行锁。fetch
当 Statement处在事务中时,锁将在事务完成时释放(事务结束了,固然此Statement也完成了)。像大多数其余数据库同样,Statement只能在其中的全部results都被读取,或者相应的Result set被关闭以后才能关闭。spa
因此若是使用了streaming results 而又想并发访问相应的表时,你就必须尽快来处理 statement 产生的result set。code
MySQL提供了一个可选的方案,即基于游标的 streaming。与逐行扫描不一样的是它能够一次性读取多行数据。要使用这种方式,你须要将 useCursorFetch 设置为true,而后调用 setFetchSize 方法来设置你但愿一次获取的行数:htm
conn = DriverManager.getConnection("jdbc:mysql://localhost/?useCursorFetch=true", "user", "s3cr3t"); stmt = conn.createStatement(); stmt.setFetchSize(100); rs = stmt.executeQuery("SELECT * FROM your_table_here");
emmm~,感受没啥好补充的了。若是内存够大就不必这么麻烦,直接默认就行了。