JDBC资源的正确使用方式

Posted

技术标签:

【中文标题】JDBC资源的正确使用方式【英文标题】:The correct way to use JDBC resources 【发布时间】:2014-04-17 16:07:44 【问题描述】:

即使在 Java 7 中,我也经常看到这样的代码

    Connection c = null;
    PreparedStatement s = null;
    try 
        c = dataSource.getConnection();

        String sql = "insert into table (column1, column2) values (?, ?);
        s = c.prepareStatement(sql);
        int i = 1;
        s.setString(i++, "111");
        s.setString(i++, "222");

        s.execute();

     catch (SQLException e) 
        log.error("failed to insert", e);
     finally 
        DbUtils.close(s, c); // closes s and c with no questions
    

但根据规范,当连接关闭时,所有语句和结果集都会被释放。

我听说 JDBC 驱动程序有可能不遵守 JDBC API 的规则,老方法更好。我的问题是听听对此的看法。代码看起来更好,但如果它很危险怎么办? 在我看来,最喜欢的方法是在此处使用 try-with-resources。够安全吗?

【问题讨论】:

“可以吗?”是个什么样的问题?你自己说过:“尝试资源”是更好的处理方式。 听说 JDBC 驱动程序有可能不按 JDBC API 的规则运行,老办法更好。我的问题是听听对此的看法。代码看起来更好,但如果它很危险怎么办? 嗯,这就是您应该在问题中提出的内容。 @FedorovMikhail '旧方法更好'?我认为这表明缺乏对 try-with-resources 工作原理的理解,因为从技术上讲,try-with-resources 可以完成您的代码所做的工作,除了较少的样板文件和实际异常反馈(如果出现任何问题)。 【参考方案1】:

资源是程序完成后必须关闭的对象。因此您不必在finally块中手动关闭对象

 String sql = "insert into table (column1, column2) values (?, ?);
    try(Connection  c = dataSource.getConnection();
    PreparedStatement s = c.prepareStatement(sql);) 


        int i = 1;
        s.setString(i++, "111");
        s.setString(i++, "222");

        s.execute();

     catch (SQLException e) 
        log.error("Failed to insert transaction", e);
     

【讨论】:

【参考方案2】:

您应该始终释放/关闭您使用的资源,例如 ResultSet、Statement、Connection。这应该在 finally 块中完成。您在此处粘贴的 sn-p 看起来不错(只要 s 和 c 在 QuietDb 中关闭)。

【讨论】:

【参考方案3】:

虽然closing a Connection will close all Statements associated with it,但在大多数数据库中,您可以同时为任何一个Connection 打开多少Statements。

如果您不关闭Statements,则会增加ORA-01000: maximum open cursors exceeded 等错误的可能性。

如果您关闭Statements、they also close their ResultSets,那么您不必同时关闭这两个。

【讨论】:

这是假设实现行为良好,但并非总是如此。完成后最好显式关闭资源。【参考方案4】:

使用try-with-resources,您的代码可以重写为:

try (
    Connection c = dataSource.getConnection();
    PreparedStatement s = c.prepareStatement("insert into table (column1, column2) values (?, ?)");
) 
    int i = 1;
    s.setString(i++, "111");
    s.setString(i++, "222");

    s.execute();
 catch (SQLException e) 
    log.error("failed to insert", e);

这保证了语句和连接都被关闭(即使关闭语句会引发异常!)。唯一的区别可能是关闭时可能会抛出异常,因为我不知道您的DbUtils.close 是否会吞下异常。

一般而言,try-with-resources 提供了更简洁的代码,并且更能确保资源以正确的顺序正确关闭,而无需太多样板。

【讨论】:

以上是关于JDBC资源的正确使用方式的主要内容,如果未能解决你的问题,请参考以下文章

Java避坑指南:finally块的陷阱及正确的关闭资源方式小

Java避坑指南:finally块的陷阱及正确的关闭资源方式小

Java避坑指南:finally块的陷阱及正确的关闭资源方式小

Java避坑指南:finally块的陷阱及正确的关闭资源方式小

5. JDBC之数据库连接池——Part2

释放资源