【问题标题】:Reusing PreparedStatement causes SQLException [duplicate]重用 PreparedStatement 导致 SQLException [重复]
【发布时间】:2016-07-15 06:41:49
【问题描述】:

尝试使用资源会给我以下异常:

java.sql.SQLException: ResultSet 关闭后不允许操作

我的代码:

public Set<Tablet> viewAllTablets(int offset, int noOfRecords) throws OutOfRangeException {
    Set<Tablet> tabletSet = new HashSet<>();
    Tablet tablet = null;

    try(Connection connection = dataSource.getConnection();
        PreparedStatement preparedStatement = connection.prepareStatement("SELECT SQL_CALC_FOUND_ROWS * FROM tablets limit " + offset + ", " + noOfRecords + ";");
        ResultSet resultSet = preparedStatement.executeQuery();
        ResultSet resultSet1 = preparedStatement.executeQuery("SELECT FOUND_ROWS()");){

        while (resultSet.next()){
            tablet = new Tablet();
            tablet.setTabletId(resultSet.getInt("idTablet"));
            tablet.setName(resultSet.getString("name"));
            tablet.setNeedRecepie(resultSet.getBoolean("need_recipe"));
            tablet.setPrice(resultSet.getDouble("price"));
            tablet.setTypeId(resultSet.getInt("type_id"));
            tablet.setDescription(resultSet.getString("description"));
            tablet.setTabletType(TypeFactory.getType(tablet.getTypeId()));
            tablet.setWeight(resultSet.getDouble("weight_of_pack"));
            tablet.setPillsCount(resultSet.getInt("pills_count"));
            tabletSet.add(tablet);
        }
        if(resultSet1.next())
            this.noOfRecords = resultSet1.getInt(1);
    } catch (SQLException e) {
        e.printStackTrace();
    }
    return tabletSet;
}

【问题讨论】:

  • 请包括 ENTIRE、COMPLETE 堆栈跟踪,并确定代码中引发异常的行。如果没有这些基本信息,没有人可以帮助您。
  • Try with resources 在 try 块完成后自动关闭打开的资源
  • @pahan:虽然这是真的,但与上述无关。在 try-with-resources 完成之后,OP 没有访问(也无法访问)那些 ResultSets。

标签: java jdbc try-with-resources


【解决方案1】:

PreparedStatement 执行第二个查询会隐式关闭前一个查询中的 ResultSet。来自Statement

默认情况下,每个Statement对象只能同时打开一个ResultSet对象。

使用两个不同的语句,这些语句(注意resultSet1 是如何检索的)虽然我当然不知道你的FOUND_ROWS 函数的要求是什么:

try (
    Connection connection = dataSource.getConnection();
    PreparedStatement preparedStatement = connection.prepareStatement("SELECT SQL_CALC_FOUND_ROWS * FROM tablets limit " + offset + ", " + noOfRecords + ";");
    ResultSet resultSet = preparedStatement.executeQuery();
    ResultSet resultSet1 = connection.createStatement().executeQuery("SELECT FOUND_ROWS()"); // ****
    ) {
    while (resultSet.next()) {
        tablet = new Tablet();
        tablet.setTabletId(resultSet.getInt("idTablet"));
        tablet.setName(resultSet.getString("name"));
        tablet.setNeedRecepie(resultSet.getBoolean("need_recipe"));
        tablet.setPrice(resultSet.getDouble("price"));
        tablet.setTypeId(resultSet.getInt("type_id"));
        tablet.setDescription(resultSet.getString("description"));
        tablet.setTabletType(TypeFactory.getType(tablet.getTypeId()));
        tablet.setWeight(resultSet.getDouble("weight_of_pack"));
        tablet.setPillsCount(resultSet.getInt("pills_count"));
        tabletSet.add(tablet);
    }
    if (resultSet1.next())
        this.noOfRecords = resultSet1.getInt(1);
} catch (SQLException e) {
    e.printStackTrace();
}

另外:不要在PreparedStatement 上使用StatementexecuteQuery(String)。它真的不应该存在,这是java.sql 包装设计中的一个缺陷。事实上,Statement#executeQuery 的文档说:

注意:不能在PreparedStatementCallableStatement 上调用此方法。

【讨论】:

  • 如果我想为preparedStatement 设置参数(例如:setInt()),我也可以在try-with-resources 块中这样做吗?在 preparedStatement 初始化之后?
  • @theyuv - 您可以使用嵌套的try-with-resources 或使用函数来创建准备好的语句并设置其参数,详细信息在the answers to this question 中。
猜你喜欢
  • 1970-01-01
  • 2010-11-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-28
  • 1970-01-01
  • 2012-05-09
相关资源
最近更新 更多