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工具類中有靜態變量,須考慮線程安全問題,能用數據庫連接池盡量使用數據庫連接池


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM