【问题标题】:Handling all exceptions when executing SQL in Java在 Java 中执行 SQL 时处理所有异常
【发布时间】:2012-11-23 10:02:07
【问题描述】:

在 Java 中执行一条 SQL 语句涉及许多步骤:

  1. 创建连接
  2. 创建语句
  3. 执行语句,创建结果集
  4. 关闭结果集
  5. 结束声明
  6. 关闭连接

在每个步骤中都可能抛出 SQLException。如果我们能够正确处理所有异常并释放所有资源,代码将如下所示,其中 4 级 TRY 相互堆叠。

try {
     Connection connection = dataSource.getConnection();
     try {
           PreparedStatement statement = connection.prepareStatement("SELECT 1 FROM myTable");
           try {
                ResultSet result = statement.executeQuery();
                try {
                     if (result.next()) {
                           Integer theOne = result.getInt(1);
                     }
                }
                finally {
                     result.close();
                }
           }
           finally {
                statement.close();
           }
     }
     finally {
           connection.close();
     }
}
catch (SQLException e) {
// Handle exception
}

您能否提出一种更好(更短)的方式来执行语句,同时释放所有消耗的资源?

【问题讨论】:

  • 用try catch 包裹整个东西?除非你想知道具体是哪里失败了。
  • 如果您将整个块包装到 try/catch 中并引发异常 - 您将不知道哪些资源已被消耗并需要关闭。
  • @user245106 我的评论有点滑稽。

标签: java sql


【解决方案1】:

查看Apache Commons DbUtils,尤其是closeQuietly() 方法。它将正确处理关闭的连接/语句/结果集,包括一个或多个为空的情况。

另一种选择是Spring JdbcTemplate,它可以从您那里抽象出很多工作,并且您可以以一种更功能的方式处理数据库查询。您只需提供一个类作为回调,以便为ResultSet 的每一行调用。它将处理迭代、异常处理和正确关闭资源。

【讨论】:

  • JdbcTemplate 不错,+1
【解决方案2】:

您的代码可以通过这种方式缩短和编写...

Connection connection = dataSource.getConnection();
PreparedStatement statement = null;
ResultSet result = null;
try {
    statement= connection.prepareStatement("SELECT 1 FROM myTable");
    result = statement.executeQuery();
    if (result.next()) {
        Integer theOne = result.getInt(1);
    }
} catch (SQLException e) {
    // Handle exception

} finally {
    if(result != null) result.close();
    if(statement != null) statement.close();
    if(connection != null) connection.close();
}

【讨论】:

  • 这个解决方案有点问题。 connection.close 也可能抛出 SQLException。
  • 好评。这很好地说明了一个简单的资源管理问题但是
【解决方案3】:

只需关闭Connection,这将释放所有资源*。您无需关闭StatementResultSet

*只要确保您没有任何活跃的交易。

【讨论】:

    【解决方案4】:
    Connection connection = null;
    PreparedStatement statement = null;
    ResultSet result = null;
    try {
         connection = dataSource.getConnection(); 
         statement = connection.prepareStatement("SELECT 1 FROM myTable");
         result = statement.executeQuery();
         if (result.next()) {
             Integer theOne = result.getInt(1);
         }
    }
    catch (SQLException e) { /* log error */ }
    finally {           
         if (result != null) try { result.close(); } catch (Exception e) {/*log error or ignore*/}
         if (statement != null) try { statement.close(); } catch (Exception e) {/*log error or ignore*/}
         if (connection != null) try { connection.close(); } catch (Exception e) {/*log error or ignore*/}
    }
    

    【讨论】:

      【解决方案5】:

      如果您使用的是 Java 7,try with resources 语句将大大缩短它,使其更易于维护:

      try (Connection conn = ds.getConnection(); PreparedStatement ps = conn.prepareStatement(queryString); ResultSet rs = ps.execute()) {
      
      } catch (SQLException e) {
          //Log the error somehow
      }
      

      请注意,关闭连接会关闭所有关联的StatementsResultSets

      【讨论】:

      • 如果你使用的是连接池,关闭连接可能不会真正关闭StatementResultSet
      • 有趣——我不知道。感谢您的提示。
      【解决方案6】:

      我用可以调用的静态方法创建了一个实用程序类:

      package persistence;
      
      // add imports.
      
      public final class DatabaseUtils {
      
          // similar for the others Connection and Statement
          public static void close(ResultSet rs) {
              try {
                  if (rs != null) {
                      rs.close();
                  }
              } catch (Exception e) {
                  LOGGER.error("Failed to close ResultSet", e);
              }
          }
      }
      

      所以你的代码是:

           Integer theOne = null;
           Connection connection = null;
           PreparedStatement statment = null;
           ResultSet result = null;
           try {
               connection = dataSource.getConnection();
               statement = connection.prepareStatement("SELECT 1 FROM myTable");
               result = statement.executeQuery();
               while (result.next()) {
                   theOne = result.getInt(1);
               }
          } catch (SQLException e) {
              // do something
          } finally {
              DatabaseUtils.close(result);
              DatabaseUtils.close(statement);
              DatabaseUtils.close(connection);
          }
          return theOne;
      

      我建议在此方法之外实例化 Connection 并将其传入。这样可以更好地处理事务。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-02-16
        • 2012-03-30
        • 2019-07-19
        • 2017-05-13
        • 1970-01-01
        相关资源
        最近更新 更多