JDBC捕获登录失败异常并重新提交输入

时间:2016-02-23 23:57:44

标签: java sql jdbc

try{
Class.forName ("oracle.jdbc.driver.OracleDriver"); // identify

Connection con = DriverManager.getConnection
 ("jdbc:oracle...",userid,password); 


// create Statement and execute sql statement after
} catch (SQLException ex) {
        Logger.getLogger(Transcript.class.getName()).log(Level.SEVERE, null, ex);
    }

我能找到的唯一例外是SQLException,但它如何区分登录失败和不正确的sql语句?

我希望它重新向用户承诺输入id和密码的另一个机会,我把它放在catch块中吗?

如果是这样,我是否需要另一个嵌套的try-catch来处理异常?

因为我想分别处理这两种情况,但似乎只有一个SQLException我可以使用。

1 个答案:

答案 0 :(得分:1)

实际上,您还会得到更多:

If you don't have the right Oracle driver in the classpath in Class.forName:
Exception in thread "main" java.lang.ClassNotFoundException: oracle.jdbc.driver.OracleDriver

If DriverManager.getConnection fails because of a wrong jdbc url syntax:
Exception in thread "main" java.sql.SQLException: No suitable driver found for jdbc:oracle...

If login/password fails at DriverManager.getConnection
Exception in thread "main" java.sql.SQLException: ORA-01017: invalid username/password; logon denied

In case of an incorrect SQL statement:
Exception in thread "main" java.sql.SQLSyntaxErrorException: ORA-00942: table or view does not exist

In case of an incorrect SQL statement:
Exception in thread "main" java.sql.SQLSyntaxErrorException: ORA-00900: invalid SQL statement

In case of an incorrect SQL statement:
Exception in thread "main" java.sql.SQLException: Invalid column name

您可以将登录失败与SQL失败分开,因为它们发生在代码中的不同位置。

public class Oracle {

    public static void main(final String[] args) throws ClassNotFoundException, SQLException {
        final Connection con;

        try {
            Class.forName ("oracle.jdbc.driver.OracleDriver"); 
        } catch (final Exception e) {
            throw new RuntimeException("Driver failure");
        }

        try {
            con = DriverManager.getConnection ("jdbc:oracle:thin:schema/password@host:port:sid");
        } catch (final Exception e) {
            throw new RuntimeException("Login failure");
        }


        try {
            final Statement stmt = con.createStatement();

            final String sql = "select 1 from dual";
            final ResultSet rs = stmt.executeQuery(sql);
            while(rs.next()) {
                // do something with the data
            }
            rs.close();
        } catch (final Exception e) {
            throw new RuntimeException("SQL failure");
        }
    }
}

注意:这是一个暴力示例,在生产代码中您可能需要更精确的异常处理程序,并且您应确保资源始终关闭。例如,如果在读取resut集时发生SQL错误并因为引用无效列而出错,则可能需要关闭语句以及结果集。

另外两个特定于Oracle的提示:

  • 不要将登录名和密码作为参数传递给DriverManager.getConnection。 Oracle连接有更多参数,构建包含所有内容的JDBC URL更容易:" jdbc:oracle:thin:schema / password @ host:port:sid"

    • 请注意,host:port是必需的。很多时候,多个Oracle服务器实例可以共享同一个端口。您可以使用服务ID(SID)来区分它们。
  • 在真正的Oracle异常的情况下,异常被包装到SQLException或SQLSyntaxErrorException,有时这个,有时是。我发现将自己的逻辑置于此之上非常方便:

    • 我通过try..catch捕获任何异常。如果错误消息以ORA-开头,则表示Oracle错误,我将其包装到自定义异常类并重新抛出。

    • 在自定义异常中解析Oracle错误代码可能很方便。您可以使用它来区分您在PL / SQL中抛出的自定义Oracle异常(-20000 ..- 20999)(并且可以指示业务级错误)。其余的错误代码总是会出现技术错误,即代码或数据库结构中出现错误。

要关闭资源(java7之前版本),请使用try..finally。请注意,在实际关闭资源时对可能的进一步异常的悲观处理失败。

Statement stmt=null;
ResultSet rs=null;
try {
    try {
        final Statement stmt = con.createStatement();
        final String sql = "select 1 from dual";
        rs = stmt.executeQuery(sql);
        while(rs.next()) {
            // do something with the data
        }
        rs.close();
        rs=null;
        stmt.close();
        stmt=null;
    } catch (final Exception e) {
        throw new RuntimeException("SQL failure");
    }
} finally {
    if (rs!=null) {
        try {
            rs.close();
        } catch (Exception e) {
            // ignore - we can't do too much
        }
    }
    if (stmt!=null) {
        try {
            stmt.close();
        } catch (Exception e) {
            // ignore - we can't do too much
        }
    }
}

要关闭Java7及更高版本的资源,您可以从尝试使用资源块中受益。见How should I use try-with-resources with JDBC?