Operation not allowed after ResultSet closed,ResultSet is from UPDATE. No Data和Column 'xxx' not found报错的解决方法
1. Operation not allowed after ResultSet closed的解决方法
报错原因:
Operation not allowed after ResultSet closed
翻译后的意思是ResultSet
关闭后不允许操作,也就是说在ResultSet
的实例调用close()
方法后,又再次使用了该实例。
解决思路:
- 查看报错处的
ResultSet
实例是否已经调用过close()方法关闭 - 报错处的
ResultSet
实例是否和其他ResultSet
实例来自的是同一个Connection
实例,就是说一个Connection
实例执行完不同的SQL语句后返回不同的ResultSet
实例。查看该Connection实例是否同时执行不同SQL语句返回ResultSet
实例
解决方法:
-
先查看
ResultSet
实例是否已经调用了close()
方法,即rs.close()
。 -
若
ResultSet
实例并未调用close()
方法,则查看生成该ResultSet
实例的Connection
实例,该Connection
实例是否还执行过其他SQL语句。若有则查看该Connection
实例是否同时执行了多条SQL语句。若同时执行了多条SQL语句,则需要在获取数据库连接到执行SQL语句的流程加上synchronized
关键字让Connection
实例在执行某个SQL语句时,不让Connection
实例同时执行其他的SQL语句,因为一个Connection实例可以对应多个Statement实例或PreparedStatement实例,但一个Statement
实例或PreparedStatement实例只能对应一个ResultSet实例。若同一个Connection实例用同一个Statement实例或PreparedStatement实例执行不同SQL语句,则两个SQL语句生成了一个ResultSet实例。 -
若
ResultSet
实例并没有调用了close()
方法,但又觉得不是该Connection
实例并未执行过多条SQL语句,则debug
查看Statement
实例或PreparedStatement
实例是否同时进入了多条SQL语句,或在控制台中打印Statement
实例或PreparedStatement
实例执行的SQL语句。控制台打印
Statement
实例或PreparedStatement
实例执行的SQL语句代码如下:/*** * 执行查询的sql语句,并返回结果集 * @param sql sql语句 * @param objects 替代占位符的数组 * @return ResultSet结果集 */ public static ResultSet executeQuery(String sql, Object... objects) { System.out.println("sql ->" + sql); connection = getConnection(); System.out.println("connection->" + connection); try { ppstmt = connection.prepareStatement(sql); System.out.println(sql + " ppstm1->" + ppstmt); if (objects != null && objects.length > 0) { for (int i = 0; i < objects.length; i++) { ppstmt.setObject(i + 1, objects[i]); } } rs = ppstmt.executeQuery(); System.out.println(sql + " ppstm->" + ppstmt); } catch (SQLException e) { System.out.println("SQL语句错误或参数个数与占位符不一致"); e.printStackTrace(); return rs; } return rs; }
报错时截图:
可以看到SQL语句和预编译后的SQ语句不相同
- 若是在JDBC工具类中将Connection,PreparedStatement或ResultSet定义成全局静态变量,则要考虑线程安全问题,可能会出现上述2的问题,将可能出现线程安全的地方同步即可。
总结:
- 先查看是否手动调用过
ResultSet
的close()
方法 - 若没有,则查看
ResultSet
实例是否只对应一个Statement
实例或PreparedStatement
实例 - 若定义了全局静态变量,考虑线程安全问题
2. ResultSet is from UPDATE. No Data的解决方法
报错原因:
ResultSet is from UPDATE. No Data
直译后的意思是ResultSet
是来自更新(添加,删除,修改语句)。没有数据。也就是说Result
的实例可能是执行增删改的SQL语句(该SQL语句不是查询语句),或者是查询语句但ResultSet
实例调用next()
方法后没有数据,即while(rs.next())
中的rs
没有数据,所以调用next()
方法会报错。
解决思路:
- 检查SQL语句是否正确
- 使用
execute
和getResultSet
方法 - 查看创建
ResultSet
实例的代码是否有问题,并一级一级往里追原因
解决方法:
- 检查SQL语句,只有查询语句执行后才会返回ResultSet
- 使用execute和getResultSet方法
- 若SQL语句正确,能在数据库中执行该SQL语句,但Java中却不行,则往上追到PreparedStatement或Statement。debug进入或在控制台打印传入的SQL语句和编译的SQL语句是否相同,若不相同,则是同一时间进入了多条SQL语句,考虑线程安全问题。在需要同步的代码块加上
synchronized
关键字。 - 若是在JDBC工具类中将Connection,PreparedStatement或ResultSet定义成全局静态变量,则要考虑线程安全问题,将可能出现线程安全的地方同步即可。
3. Column 'xxx' not found的解决方法
报错原因:
Column 'xxx' not found
直译的意思就是没有找到xxx这一列,也就是说,查询的结果中,没有该字段的列。
解决思路:
- 检查SQL语句是否正确
- 检查编译后的SQL语句是否和预期的SQL语句相同
解决方法:
- 检查SQL语句是否正确,比如
select name from user;
,在Java中却是rs.getString("password");
,或者是select nam from user;
,在Java中rs.getString("name");
认真检查一下修改即可。 debug
进入PreparedStatement或Statement
,或控制台打印PreparedStatement
或Statement
编译后的SQL语句和传入的SQL语句是否相同
报错截图:
上图可知传入的SQL语句和编译后的SQL语句不同
再看下报错处的代码
/**
* 查找所有学生
*
* @return 学生集合
*/
@Override
public ArrayList<Student> selectAllStudent() {
String sql = "SELECT * FROM db_studentinfo";
ArrayList<Student> studentList = null;
ResultSet rs = JDBCUtil.executeQuery(sql);
try {
studentList = new ArrayList<Student>();
while (rs.next()) {
studentList.add(setStudent(rs));
}
} catch (SQLException e) {
e.printStackTrace();
return studentList;
} finally {
JDBCUtil.closeDB();
}
return studentList;
}
// 将查询的结果集放入学生对象中
private Student setStudent(ResultSet rs) {
Student student = null;
try {
student = new Student();
student.setStudentNum(rs.getInt("学生学号"));
student.setStudentName(rs.getString("学生姓名"));
student.setGrade(rs.getString("年级"));
student.setStudentClass(rs.getString("班级"));
student.setSex(rs.getString("性别"));
student.setAge(rs.getInt("年龄"));
student.setAddress(rs.getString("家庭住址"));
student.setPhone(rs.getString("联系电话"));
} catch (SQLException e) {
e.printStackTrace();
return student;
}
return student;
}
因为此时是两条SQL语句同时进入PreparedStatement
实例中,所以虽然传入的是正确的SQL语句,但是由于其他的SQL语句也进入了,所以导致查询返回的结果集并不是我们一开始传入的SQL语句的结果集,故会报
Column '学生学号' not found.
的错误。从线程安全方面排查原因,比如在可能导致两条SQL语句同时进入PreparedStatement
实例的代码块中加synchronize
关键字进行同步。
- 若是在JDBC工具类中将Connection,PreparedStatement或ResultSet定义成全局静态变量,则要考虑线程安全问题,将可能出现线程安全的地方同步即可。
总结
- 先检查SQL语句是否正确
- 理清链路
加载JDBC驱动
-->Connection
-->PreparedStatement
-->ResultSet
,先想到最有可能出错的地方,打断点debug进去或控制台打印可能出错的变量 - 若没有使用数据库连接池,如果JDBC工具类中有静态变量,须考虑线程安全问题,能用数据库连接池尽量使用数据库连接池