1、簡介
當JDBC在與數據源交互期間遇到錯誤時,它將拋出SQLException實例,而不是Exception。
SQLException 實例包含以下信息,可以幫助您確定錯誤原因:
1、error 的描述: 調用方法SQLException.getMessage檢索包含此描述的String對象。
2、SQLState 代碼: 這些代碼及其各自的含義已由 ISO/ANSI 和 Open Group (X/Open) 進行了標準化,另外還有些代碼留給數據庫供應商自己定義。 此String對象由五個字母數字字符組成。 通過調用方法 SQLException.getSQLState 檢索此代碼。
3、錯誤代碼: 這是一個整數值,用於標識導致引發SQLException實例的錯誤。 它的值和含義是特定於實現的,並且可能是基礎數據源返回的實際錯誤代碼。 通過調用方法SQLException.getErrorCode檢索錯誤。
4、原因: SQLException 實例可能具有因果關係,該因果關係由導致拋出SQLException實例的一個或多個Throwable對象組成。要獲取這一系列原因信息,要遞歸調用方法SQLException.getCause 獲取,直到返回空值。
5、對任何鏈接的異常的引用: 如果發生多個錯誤,則可以通過該異常引用鏈獲取異常。 通過對引發的異常調用方法 SQLException.getNextException 來檢索這些異常。
2、異常(Exceptions)
下面我們編寫一個通用方法來檢索SQLException中包含的SQLState,錯誤代碼,錯誤描述和原因(如果有的話)以及與其鏈接的任何其他異常:
private static String sql = "select id,name,email,country,password from Userswhere id=1";
public static void main(String[] args) {
// Step 1: 創建連接對象 connection
try (Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/lkf_db?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT", "root", "root");
// Step 2:使用 connection 創建 stmt
Statement stmt = connection.createStatement();
// Step 3:執行SQL語句
ResultSet rs = stmt.executeQuery(sql)) {
//獲取結果集 rs 的元數據對象 resultSetMetaData
ResultSetMetaData resultSetMetaData = rs.getMetaData();
System.out.println("1. 列數量 :: " + resultSetMetaData.getColumnCount());
System.out.println("2. 第一列名稱 :: " + resultSetMetaData.getColumnName(1));
System.out.println("3. 數據庫名稱 :: " + resultSetMetaData.getCatalogName(1));
;
System.out.println("4. 列數據類型 :: " + resultSetMetaData.getColumnTypeName(1));
System.out.println("5. 表名 :: " + resultSetMetaData.getTableName(1));
} catch (SQLException e) {
printSQLException(e);
}
}
public static void printSQLException(SQLException ex) {
for (Throwable e : ex) {
if (e instanceof SQLException) {
if (!ignoreSQLException(((SQLException) e).getSQLState())) {
e.printStackTrace(System.err);
System.err.println("SQLState: " + ((SQLException) e).getSQLState());
System.err.println("Error Code: " + ((SQLException) e).getErrorCode());
System.err.println("Message: " + e.getMessage());
Throwable t = ex.getCause();
while (t != null) {
System.out.println("Cause: " + t);
t = t.getCause();
}
}
}
}
}
public static boolean ignoreSQLException(String sqlState) {
if (sqlState == null) {
System.out.println("The SQL state is not defined!");
return false;
}
// X0Y32: Jar文件已存在
if (sqlState.equalsIgnoreCase("X0Y32"))
return true;
// 42Y55: 該表已存在
if (sqlState.equalsIgnoreCase("42Y55"))
return true;
return false;
}
輸出結果如下:
java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '=1' at line 1
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:120)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
at com.mysql.cj.jdbc.StatementImpl.executeQuery(StatementImpl.java:1218)
at com.lkf.jdbc.SQLExceptionDemo.main(SQLExceptionDemo.java:13)
SQLState: 42000
Error Code: 1064
Message: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '=1' at line 1
3、警告(Warnings)
SQLWarning 對象是SQLException的子類,用於處理數據庫訪問警告。 警告不會像異常一樣終止應用程序的執行。 它們只是警告用戶某些事情沒有按計劃進行。
以下方法說明了如何獲取有關Statement或ResultSet對象上報告的所有警告的完整信息:
public static void getWarningsFromResultSet(ResultSet rs)
throws SQLException {
printWarnings(rs.getWarnings());
}
public static void getWarningsFromStatement(Statement stmt)
throws SQLException {
printWarnings(stmt.getWarnings());
}
public static void printWarnings(SQLWarning warning)
throws SQLException {
if (warning != null) {
System.out.println("\n---Warning---\n");
while (warning != null) {
System.out.println("Message: " + warning.getMessage());
System.out.println("SQLState: " + warning.getSQLState());
System.out.print("Vendor error code: ");
System.out.println(warning.getErrorCode());
System.out.println("");
warning = warning.getNextWarning();
}
}
}
最常見的警告是DataTruncation警告,它是SQLWarning的子類。 所有DataTruncation對象的SQLState均爲01004,表示讀取或寫入數據有問題。
使用DataTruncation方法,您可以找出在哪個列或參數數據中被截斷,截斷是在讀取還是寫入操作上進行的,應該傳送多少字節以及實際傳送了多少字節。
4、SQLException 分類
JDBC驅動程序可能會拋出SQLException的子類,該子類對應於與特定SQLState類值不相關的常見SQLState或常見錯誤狀態。 這使我們可以編寫更多可移植的錯誤處理代碼。 這些異常是以下類別之一的子類:
- SQLNonTransientException
- SQLTransientException
- SQLRecoverableException
5、SQLException的其他子類
BatchUpdateException
在批處理更新操作期間發生錯誤時,將引發BatchUpdateException。 除了SQLException提供的信息外,BatchUpdateException還提供錯誤發生之前已執行的所有語句的更新計數。
SQLClientInfoException
無法在連接上設置一個或多個客戶端信息屬性時,將引發SQLClientInfoException。 除了SQLException提供的信息外,SQLClientInfoException還提供未設置的客戶端信息屬性的列表。