在Java中关闭数据库连接的合适方法是什么?

时间:2014-08-22 13:46:49

标签: java jdbc

我试图关闭数据库连接。但是有点混乱,比如说

ResultSet rs = null 

我是否必须靠近

rs.close();

或者

DatabaseUtil.closeResultSet(rs);

这些之间有什么区别?

7 个答案:

答案 0 :(得分:1)

关闭resultSet不会关闭数据库连接。你需要单独完成。

通常你想要关闭这样的资源:

if (resultSet != null) {
     try {
         resultSet.close();
     } catch (SQLException e) {
         log.info("closing resultset caused exception", e);
     }
}

如果这是您的DatabaseUtil所做的,那么这将是更可取的。

使用try-with-resources会产生更漂亮的代码,但要注意一个边缘情况的行为是非常不同的。如果在关闭resultSet时抛出异常(在其他所有操作都没有问题之后),则使用上面的代码它不会传播,因此它不会阻止事务的其余部分完成。但是,如果使用try-with-resources,则close方法抛出的异常将被传播。关闭resultSet或语句时抛出的异常只是释放数据库资源(无论如何最终都会被释放,它不是危机),它并不表示任何数据问题而且它没有似乎是破坏数据库操作的一个原因。

关闭resultSet后应关闭数据库连接。确保使用finally块,以便无论抛出什么异常(包括关闭语句或resultSets时抛出的异常),都会关闭连接。

code in this question如何做到这一点的一个例子(可能OP希望最小化示例中的样板,因为关闭事物不是重点问题,所以可能是这样,为了保持简短,不是因为OP不知道不这样做,它表明在现实生活中发生的常见错误:

Class Class1<T>
{
  public T getColumn(DataSource ds)
  {
    T value = null;
    Connection con = null;
    Statement st = null;

    try
    {
      con = ds.getConnection();
      st = con.createStatement();
      ResultSet rs = st.executeQuery("select 1 from dual");
      rs.next();
      Object o = rs.getObject(1); // I want an Integer but a BigDecimal is created!
      value = (T) o; // ClassCastException here!
    }
    finally
    {
      if (st != null) { st.close(); }
      if (con != null) { con.close(); }
    }

    return i;
  }
}

如果statement.close抛出SQLException,则finally块中的以下行永远不会被调用,连接将不会被关闭,并且数据库连接将在未使用之前挂起,直到超时。这可能看起来不是很糟糕,因为它只有一个连接,但是每个其他连接都可能看到相同的行为,并且在适当的情况下,您可以通过这种方式将整个应用程序放下(丢弃所有数据库连接)。请参阅Michael Nygard's book Release It!,了解描述非常昂贵且令人痛苦的企业应用程序中断的故事,该故障可追溯到与此类似的代码。

必须剪切和粘贴这个资源关闭代码是丑陋的,引入类似于传递结果集映射器的模板方法会有所改进,因此关闭只在一个地方完成。但这会让你重新发明spring-jdbc,这已经为你做了这一切。

答案 1 :(得分:1)

这些方法仅关闭ResultSet。您仍然必须关闭所有StatementConnection个实例。我建议在finally块中这样做。像,

Connection conn = null;
Statement stmt = null'
ResultSet rs = null;
try {
  conn = getConnection();
  stmt = conn.prepareStatement(sql);
  stmt.setString(1, "Hello"); 
  rs = stmt.executeQuery();
  while (rs.next()) {
    // ...
  }
} catch (SQLException se) {
  se.printStackTrace();
} finally {
  if (rs != null) {
    try {
      rs.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  if (stmt != null) {
    try {
      stmt.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  if (conn != null) {
    try {
      conn.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

如果您使用我的Close utility,则可以使用finally块

} finally {
  Close.close(rs, stmt, conn);
}

答案 2 :(得分:0)

jdbc api告诉我们关闭连接将关闭结果集和语句。结束语句将关闭结果集。但我总是关闭每一个结果集和每一个声明,因为我遇到的问题不是这样做的。 只需使用结果集,语句和连接提供的close方法。

答案 3 :(得分:0)

我认为最好的方法是在try-with-resources

内完成所有事情
try(conn=openConnection()){
  try(rs=conn.getResultSet()){
  }
}

这样您就可以完全确定资源将在最后正确关闭。

答案 4 :(得分:0)

两种方式都有效,但我更喜欢第一个rs.close(); ,没有伪造检查rs是否为空并且通过try..catch语句封闭你的调用,所以你必须在最后一个块中关闭你的连接,即使Java7为你关闭所有。

检查Java / JDBC: Best design pattern to close database connection when exception occurs

答案 5 :(得分:0)

普通代码如下所示:

Connection connection = null;
PreparedStatement stmt = null;
ResultSet rs = null;
ResultSet rs2 = null;
try {
  connection = getConnection();
  stmt = connection.prepareStatement("...");

  stmt.setString(":foobar", "Foobar");
  rs = stmt.execute ... ; // I don't remember the method return ResultSet

  while (rs.next()) {
    ...
  }

  stmt.setString(":foobar", "Barfoo");
  rs2 = stmt.execute ... ; 


} finally {
  if (null != rs2) try {rs2.close();} catch (Exception e)
  if (null != rs) try {rs.close();} catch (Exception e) {...}
  if (null != stmt) try {stmt.close();} catch (Exception e) {...}
  if (null != connection) try {connection.close();} catch (Exception e) {...}
}

或者,在Java 7中,使用 try-with-resources (前面的代码几乎相同):

try (Connection connection = getConnection();
     PreparedStatement stmt = connection.prepareStatement("...")) {

  stmt.setString(":foobar", "Foobar");
  try (ResultSet rs = stmt.executeQuery()) {
    while (rs.next()) {
        ...
    }
  }
  stmt.setString(":foobar", "Barfoo");
  try (ResultSet rs2 = stmt.executeQuery()) {
    while (rs2.next()) {
        ...
    }
  }
}

区别很简单:

  • 关闭ResultSet - 以释放相关资源。在这个例子中,我使用了PreparedStatement:你可以有参数,因此不同ResultSet。因为它占用了内存和资源,所以你需要在完成它们之后关闭它们,否则垃圾收集器将会这样做,它只会回收内存。
  • 当您不再需要时关闭PreparedStatementStatement。关闭语句会关闭关联的ResultSet
  • 当您不再需要时关闭Connection。关闭连接会关闭Statement s(及其ResultSet)。

根据您的需要(例如:批处理与Web服务器),您可能不必在Java退出时关闭连接,但在不再需要资源时更好地释放资源(无论是否是JDBC资源或文件资源......)。

答案 6 :(得分:0)

关闭resultSet不会关闭数据库连接。我们应该关闭连接,如下所示。 在关闭连接之前,您应该关闭另一个实例,如ResultSet,PreparedStatement和Statement实例。

例如

 Connection con = DBUtils.getConnection();
 ....
 PreparedStatemet pstmt = con.getPreparedStatement();
 ResultSet rs = pstmt.execute();

 while(rs.next())
 {
 }

//完成ResultSet后......现在是关闭/释放实例的时候了。

    if (resultSet != null) {
    try {
    resultSet.close();
    resultSet = null;
    } catch (SQLException e) {
      // ignore the exceptions.
    }
    }

    // Close the Prepared Statement
    if(theStatement != null)
    {
    try
    {
    theStatement.close();
    theStatement = null;
    }
    catch(Exception ignored)
    {
    }

// Close the Connection
    if(theConnection != null)
    {
    try
    {
    theConnection.close();
    theConnection = null;
    }
    catch(Exception ignored)
    {
    }