Handling SQLExceptions

此页面包含以下主题:

SQLException 概述

当 JDBC 在与数据源进行交互期间遇到错误时,它将抛出SQLException而不是Exception的实例。 (在这种情况下,数据源表示Connection对象连接到的数据库.)SQLException实例包含以下信息,可以帮助您确定错误原因:

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

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

  • 错误代码。这是一个整数值,用于标识导致引发SQLException实例的错误。其值和含义是特定于实现的,并且可能是基础数据源返回的实际错误代码。通过调用方法SQLException.getErrorCode检索错误。

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

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

Retrieving Exceptions

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

public static void printSQLException(SQLException ex) {

    for (Throwable e : ex) {
        if (e instanceof SQLException) {
            if (ignoreSQLException(
                ((SQLException)e).
                getSQLState()) == false) {

                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();
                }
            }
        }
    }
}

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

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

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

public static boolean ignoreSQLException(String sqlState) {

    if (sqlState == null) {
        System.out.println("The SQL state is not defined!");
        return false;
    }

    // X0Y32: Jar file already exists in schema
    if (sqlState.equalsIgnoreCase("X0Y32"))
        return true;

    // 42Y55: Table already exists in schema
    if (sqlState.equalsIgnoreCase("42Y55"))
        return true;

    return false;
}

Retrieving Warnings

SQLWarning对象是SQLException的子类,用于处理数据库访问警告。警告不会像异常一样停止应用程序的执行。它们只是警告用户某些事情没有按计划发生。例如,警告可能会让您知道您try撤消的特权未被撤消。否则,警告可能会告诉您在请求的断开连接期间发生了错误。

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

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

public static void getWarningsFromResultSet(ResultSet rs)
    throws SQLException {
    JDBCTutorialUtilities.printWarnings(rs.getWarnings());
}

public static void getWarningsFromStatement(Statement stmt)
    throws SQLException {
    JDBCTutorialUtilities.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方法可让您找出截断了哪些列或参数数据,截断是在读取还是写入操作上进行的,应该传送多少字节以及实际传送了多少字节。

Categorized SQLExceptions

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

  • SQLNonTransientException

  • SQLTransientException

  • SQLRecoverableException

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

SQLException 的其他子类

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

  • 在批处理更新操作期间发生错误时,将引发BatchUpdateException。除了SQLException提供的信息之外,BatchUpdateException还提供错误发生之前已执行的所有语句的更新计数。

  • 无法在连接上设置一个或多个 Client 端信息属性时,将引发SQLClientInfoException。除了SQLException提供的信息之外,SQLClientInfoException还提供了未设置的 Client 端信息属性的列表。