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实例

解决方法:

  1. 先查看ResultSet实例是否已经调用了close()方法,即rs.close()

  2. 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实例。

  3. 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语句不相同
  1. 若是在JDBC工具类中将Connection,PreparedStatement或ResultSet定义成全局静态变量,则要考虑线程安全问题,可能会出现上述2的问题,将可能出现线程安全的地方同步即可。

总结:

  • 先查看是否手动调用过ResultSetclose()方法
  • 若没有,则查看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语句是否正确
  • 使用executegetResultSet方法
  • 查看创建ResultSet实例的代码是否有问题,并一级一级往里追原因

解决方法:

  1. 检查SQL语句,只有查询语句执行后才会返回ResultSet
  2. 使用execute和getResultSet方法
  3. 若SQL语句正确,能在数据库中执行该SQL语句,但Java中却不行,则往上追到PreparedStatement或Statement。debug进入或在控制台打印传入的SQL语句和编译的SQL语句是否相同,若不相同,则是同一时间进入了多条SQL语句,考虑线程安全问题。在需要同步的代码块加上synchronized关键字。
  4. 若是在JDBC工具类中将Connection,PreparedStatement或ResultSet定义成全局静态变量,则要考虑线程安全问题,将可能出现线程安全的地方同步即可。

3. Column 'xxx' not found的解决方法

报错原因:

Column 'xxx' not found直译的意思就是没有找到xxx这一列,也就是说,查询的结果中,没有该字段的列。

解决思路:

  • 检查SQL语句是否正确
  • 检查编译后的SQL语句是否和预期的SQL语句相同

解决方法:

  1. 检查SQL语句是否正确,比如select name from user;,在Java中却是rs.getString("password");,或者是select nam from user;,在Java中rs.getString("name");认真检查一下修改即可。
  2. debug进入PreparedStatement或Statement,或控制台打印PreparedStatementStatement编译后的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关键字进行同步。

  1. 若是在JDBC工具类中将Connection,PreparedStatement或ResultSet定义成全局静态变量,则要考虑线程安全问题,将可能出现线程安全的地方同步即可。

总结

  • 先检查SQL语句是否正确
  • 理清链路 加载JDBC驱动 --> Connection --> PreparedStatement --> ResultSet ,先想到最有可能出错的地方,打断点debug进去或控制台打印可能出错的变量
  • 若没有使用数据库连接池,如果JDBC工具类中有静态变量,须考虑线程安全问题,能用数据库连接池尽量使用数据库连接池
posted @ 2020-04-01 21:45  Windows_XP  阅读(2981)  评论(0编辑  收藏  举报