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