SSH隧道连接MySQL后,JDBC代码执行rs.last()抛出ResultSet类型不允许操作的SQLException问题
SSH隧道连接MySQL后,JDBC代码执行rs.last()抛出ResultSet类型不允许操作的SQLException问题
嘿,这个问题其实和SSH隧道本身没啥关系,核心是你创建的ResultSet默认类型不支持游标来回移动操作!
先给你拆解下报错原因:当你调用rs.last()时,JDBC抛出Operation not allowed for a result set of type ResultSet.TYPE_FORWARD_ONLY,这是因为默认情况下,通过connection.prepareStatement(sql)创建的PreparedStatement,生成的ResultSet是只能单向向前遍历的类型(TYPE_FORWARD_ONLY),这种类型不允许调用last()、beforeFirst()这类需要移动游标到非当前位置之后的操作。之前你的代码能正常运行,大概率是之前的环境里JDBC驱动或连接配置无意中帮你设置了可滚动的ResultSet,但换了SSH隧道连接后(其实本质是连接配置没改,只是现在默认行为生效了),就触发了这个限制。
解决方法很简单:创建PreparedStatement时显式指定可滚动的ResultSet类型
修改你创建PreparedStatement的代码,加上ResultSet类型和并发模式参数:
// 替换原来的ps = connection.prepareStatement(mark_complete); ps = connection.prepareStatement(mark_complete, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
ResultSet.TYPE_SCROLL_INSENSITIVE:允许游标自由滚动(前后移动都可以),且对数据库的修改不会反映到ResultSet中(适合你的只读场景)ResultSet.CONCUR_READ_ONLY:设置ResultSet为只读模式,符合你只是读取数据写入Excel的需求
顺便提下你代码里的两个小问题
- 代码里的
connection.createStatement();这行完全没用,你创建了一个Statement对象但没赋值给任何变量,也没使用,属于无效代码,建议删掉,避免浪费资源。 - 你的while循环逻辑有点问题:在for循环里又调用了一次
rs.next(),结合外层的rs.next()和while (r < size),可能会导致游标移动异常,甚至跳过部分数据。建议梳理下遍历逻辑,比如改成:
int index = 0; while (rs.next()) { index++; Row row = sheet.createRow((short) index); String value1 = rs.getString(1); row.createCell(0).setCellValue(value1); String value2 = StringUtils.left(rs.getString(2), 16); row.createCell(1).setCellValue(value2); }
这样直接用rs.next()来遍历,既简洁又不容易出错,还能省去调用rs.last()获取行数的步骤(如果不是必须要提前知道行数的话)。
备注:内容来源于stack exchange,提问作者David S.
相关产品推荐
相关产品推荐

