处理 SQLExceptions

原文: https://docs.oracle.com/javase/tutorial/jdbc/basics/sqlexception.html

此页面包含以下主题:

当 JDBC 在与数据源交互期间遇到错误时,它会抛出SQLException的实例,而不是Exception。 (此上下文中的数据源表示Connection对象所连接的数据库。)SQLException实例包含以下信息,可帮助您确定错误原因:

  • 错误的描述。通过调用方法SQLException.getMessage检索包含此描述的String对象。

  • 一个 SQLState 代码。这些代码及其各自的含义已经由 ISO / ANSI 和 Open Group(X / Open)标准化,尽管已经为数据库供应商保留了一些代码来自行定义。此String对象由五个字母数字字符组成。通过调用方法SQLException.getSQLState检索此代码。

  • 错误代码。这是一个整数值,用于标识导致SQLException实例被抛出的错误。它的值和含义是特定于实现的,可能是底层数据源返回的实际错误代码。通过调用方法SQLException.getErrorCode来检索错误。

  • 一个原因。 SQLException实例可能具有因果关系,该关系由一个或多个Throwable对象组成,这些对象导致SQLException实例被抛出。要导航此原因链,请递归调用方法SQLException.getCause,直到返回null值。

  • 对任何链式例外的引用。如果发生多个错误,则通过此链引用异常。通过在抛出的异常上调用方法SQLException.getNextException来检索这些异常。

以下方法JDBCTutorialUtilities.printSQLException输出SQLException中包含的 SQLState,错误代码,错误描述和原因(如果有)以及链接到它的任何其他异常:

  1. public static void printSQLException(SQLException ex) {
  2. for (Throwable e : ex) {
  3. if (e instanceof SQLException) {
  4. if (ignoreSQLException(
  5. ((SQLException)e).
  6. getSQLState()) == false) {
  7. e.printStackTrace(System.err);
  8. System.err.println("SQLState: " +
  9. ((SQLException)e).getSQLState());
  10. System.err.println("Error Code: " +
  11. ((SQLException)e).getErrorCode());
  12. System.err.println("Message: " + e.getMessage());
  13. Throwable t = ex.getCause();
  14. while(t != null) {
  15. System.out.println("Cause: " + t);
  16. t = t.getCause();
  17. }
  18. }
  19. }
  20. }
  21. }

例如,如果使用 Java DB 作为 DBMS 调用方法CoffeesTable.dropTable,表COFFEES不存在,删除对JDBCTutorialUtilities.ignoreSQLException的调用,输出将类似于以下:

  1. SQLState: 42Y55
  2. Error Code: 30000
  3. Message: 'DROP TABLE' cannot be performed on
  4. 'TESTDB.COFFEES' because it does not exist.

您可以改为首先检索SQLState,然后相应地处理SQLException,而不是输出SQLException信息。例如,如果SQLState等于代码42Y55(并且您使用 Java DB 作为 DBMS),方法JDBCTutorialUtilities.ignoreSQLException将返回true,这会导致JDBCTutorialUtilities.printSQLException忽略SQLException

  1. public static boolean ignoreSQLException(String sqlState) {
  2. if (sqlState == null) {
  3. System.out.println("The SQL state is not defined!");
  4. return false;
  5. }
  6. // X0Y32: Jar file already exists in schema
  7. if (sqlState.equalsIgnoreCase("X0Y32"))
  8. return true;
  9. // 42Y55: Table already exists in schema
  10. if (sqlState.equalsIgnoreCase("42Y55"))
  11. return true;
  12. return false;
  13. }

SQLWarning对象是SQLException的子类,用于处理数据库访问警告。警告不会像例外那样停止执行应用程序;他们只是提醒用户某些事情没有按计划发生。例如,警告可能会让您知道您尝试撤销的权限未被撤销。或者警告可能会告诉您在请求的断开连接期间发生了错误。

可以在Connection对象,Statement对象(包括PreparedStatementCallableStatement对象)或ResultSet对象上报告警告。这些类中的每一个都有一个getWarnings方法,您必须调用该方法才能看到在调用对象上报告的第一个警告。如果getWarnings返回警告,您可以调用SQLWarning方法getNextWarning以获取任何其他警告。执行语句会自动清除先前语句中的警告,因此它们不会构建。但是,这意味着如果要检索语句上报告的警告,则必须在执行另一个语句之前执行此操作。

[JDBCTutorialUtilities](gettingstarted.html)中的以下方法说明了如何获取有关StatementResultSet对象上报告的任何警告的完整信息:

  1. public static void getWarningsFromResultSet(ResultSet rs)
  2. throws SQLException {
  3. JDBCTutorialUtilities.printWarnings(rs.getWarnings());
  4. }
  5. public static void getWarningsFromStatement(Statement stmt)
  6. throws SQLException {
  7. JDBCTutorialUtilities.printWarnings(stmt.getWarnings());
  8. }
  9. public static void printWarnings(SQLWarning warning)
  10. throws SQLException {
  11. if (warning != null) {
  12. System.out.println("\n---Warning---\n");
  13. while (warning != null) {
  14. System.out.println("Message: " + warning.getMessage());
  15. System.out.println("SQLState: " + warning.getSQLState());
  16. System.out.print("Vendor error code: ");
  17. System.out.println(warning.getErrorCode());
  18. System.out.println("");
  19. warning = warning.getNextWarning();
  20. }
  21. }

最常见的警告是DataTruncation警告,SQLWarning的子类。所有DataTruncation对象的 SQLState 都为01004,表示读取或写入数据时出现问题。 DataTruncation方法可以让您找出截断的列或参数数据,截断是在读操作还是写操作,应该传输了多少字节,以及实际传输了多少字节。

您的 JDBC 驱动程序可能会抛出SQLException的子类,该子类对应于常见的 SQLState 或与特定 SQLState 类值无关的常见错误状态。这使您可以编写更多可移植的错误处理代码。这些异常是以下类之一的子类:

  • SQLNonTransientException
  • SQLTransientException
  • SQLRecoverableException

有关这些子类的更多信息,请参阅java.sql软件包的最新 Javadoc 或 JDBC 驱动程序的文档。

的其他子类

还可以抛出以下SQLException的子类:

  • 批量更新操作期间发生错误时抛出BatchUpdateException。除了SQLException提供的信息之外,BatchUpdateException还提供了在错误发生之前执行的所有语句的更新计数。
  • 无法在 Connection 上设置一个或多个客户端信息属性时抛出SQLClientInfoException。除了SQLException提供的信息之外,SQLClientInfoException还提供了未设置的客户端信息属性列表。