重用 PreparedStatement 导致 SQLException
Reusing PreparedStatement causes SQLException
尝试使用资源会出现以下异常:
java.sql.SQLException: Operation not allowed after ResultSet closed
我的代码:
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;
}
在 PreparedStatement
上执行第二个查询会隐式关闭前一个查询中的 ResultSet
。来自 Statement
:
By default, only one ResultSet
object per Statement
object can be open at the same time.
使用两个不同的语句,大致如下(注意 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
上使用 Statement
的 executeQuery(String)
。它真的不应该存在,它是 java.sql
包设计中的一个缺陷。事实上,Statement#executeQuery
的文档说:
Note:This method cannot be called on a PreparedStatement
or CallableStatement
.
尝试使用资源会出现以下异常:
java.sql.SQLException: Operation not allowed after ResultSet closed
我的代码:
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;
}
在 PreparedStatement
上执行第二个查询会隐式关闭前一个查询中的 ResultSet
。来自 Statement
:
By default, only one
ResultSet
object perStatement
object can be open at the same time.
使用两个不同的语句,大致如下(注意 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
上使用 Statement
的 executeQuery(String)
。它真的不应该存在,它是 java.sql
包设计中的一个缺陷。事实上,Statement#executeQuery
的文档说:
Note:This method cannot be called on a
PreparedStatement
orCallableStatement
.