# 处理 SQLExceptions

> 原文： [https://docs.oracle.com/javase/tutorial/jdbc/basics/sqlexception.html](https://docs.oracle.com/javase/tutorial/jdbc/basics/sqlexception.html)

此页面包含以下主题：

*   [SQLException 概述](#overview_sqlexception)
*   [检索异常](#retrieving_exceptions)
*   [检索警告](#retrieving_warnings)
*   [分类 SQLExceptions](#categorized_sqlexceptions)
*   [SQLException](#subclasses_sqlexception) 的其他子类

当 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，错误代码，错误描述和原因（如果有）以及链接到它的任何其他异常：

```
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;
}

```

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

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

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

```
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`方法可以让您找出截断的列或参数数据，截断是在读操作还是写操作，应该传输了多少字节，以及实际传输了多少字节。

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

*   `SQLNonTransientException`
*   `SQLTransientException`
*   `SQLRecoverableException`

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

##  的其他子类

还可以抛出以下`SQLException`的子类：

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