编程语言
首页 > 编程语言> > java – 尝试/尝试使用资源以及Connection,Statement和ResultSet关闭

java – 尝试/尝试使用资源以及Connection,Statement和ResultSet关闭

作者:互联网

我最近和我的教授讨论了如何处理基本的jdbc连接方案.假设我们想要执行两个查询,这就是他的建议

public void doQueries() throws MyException{
    Connection con = null;
    try {
        con = DriverManager.getConnection(dataSource);
        PreparedStatement s1 = con.prepareStatement(updateSqlQuery);
        PreparedStatement s2 = con.prepareStatement(selectSqlQuery);

        // Set the parameters of the PreparedStatements and maybe do other things

        s1.executeUpdate();
        ResultSet rs = s2.executeQuery();

        rs.close();
        s2.close();
        s1.close();
    } catch (SQLException e) {
        throw new MyException(e);
    } finally {
        try {
            if (con != null) {
                con.close();
            }
        } catch (SQLException e2) {
            // Can't really do anything
        }
    }
}

我不喜欢这种方法,我有两个问题:

1.A)我认为,如果在我们做“其他事情”或者在rs.close()或s2.close()行中抛出任何异常,那么当方法结束时s1将不会被关闭.我是对的吗?

1.B)教授一直要求我明确关闭ResultSet(即使Statement语句明确说明它将关闭ResultSet)她说Sun推荐它.有什么理由这样做吗?

现在我认为这是同一件事的正确代码:

public void doQueries() throws MyException{
    Connection con = null;
    PreparedStatement s1 = null;
    PreparedStatement s2 = null;
    try {
        con = DriverManager.getConnection(dataSource);
        s1 = con.prepareStatement(updateSqlQuery);
        s2 = con.prepareStatement(selectSqlQuery);

        // Set the parameters of the PreparedStatements and maybe do other things

        s1.executeUpdate();
        ResultSet rs = s2.executeQuery();

    } catch (SQLException e) {
        throw new MyException(e);
    } finally {
        try {
            if (s2 != null) {
                s2.close();
            }
        } catch (SQLException e3) {
            // Can't do nothing
        }
        try {
            if (s1 != null) {
                s1.close();
            }
        } catch (SQLException e3) {
            // Can't do nothing
        }
        try {
            if (con != null) {
                con.close();
            }
        } catch (SQLException e2) {
            // Can't do nothing
        }
    }
}

2.A)这段代码是否正确? (当方法结束时,是否保证全部关闭?)

2.B)这是非常庞大和冗长的(如果有更多的陈述,它会变得更糟)有没有更简单或更优雅的方式来做到这一点,而不使用try-with-resources?

最后这是我最喜欢的代码

public void doQueries() throws MyException{
    try (Connection con = DriverManager.getConnection(dataSource);
         PreparedStatement s1 = con.prepareStatement(updateSqlQuery);
         PreparedStatement s2 = con.prepareStatement(selectSqlQuery))
    {

        // Set the parameters of the PreparedStatements and maybe do other things

        s1.executeUpdate();
        ResultSet rs = s2.executeQuery();

    } catch (SQLException e) {
        throw new MyException(e);
    }
}

3)这段代码是否正确?我认为我的教授不喜欢这种方式,因为没有明确关闭ResultSet,但是她告诉我她很好,只要在文档中很清楚所有关闭.您是否可以通过类似示例提供官方文档的任何链接,或者根据文档显示此代码没有问题?

解决方法:

TL;博士

>理论上,关闭语句会关闭结果集.
>在实践中,一些错误的JDBC驱动程序实现未能如此做到这一点,这是出了名的.因此,教练的建议是她从硬敲门学校那里学到的.除非您熟悉可能为应用程序部署的每个JDBC驱动程序的每个实现,否则请使用try-with-resources自动关闭JDBC工作的每个级别,例如语句和结果集.

使用try-with-resources语法

您的所有代码都没有完全使用try-with-resources.在try-with-resources语法中,您可以在大括号之前在括号中声明并实例化Connection,PreparedStatement和ResultSet.

虽然您的ResultSet未在上一个代码示例中显式关闭,但应在其语句关闭时间接关闭它.但是如下所述,由于JDBC驱动程序错误,它可能无法关闭.

AutoCloseable

实现AutoCloseable的任何此类对象将自动调用其close方法.所以不需要那些最终的条款.

对于阅读本文的人文专业,是的,Java团队拼错了“可关闭”.

你怎么知道哪些对象是可以自动关闭的,哪些不是?查看他们的类文档,看看它是否将AutoCloseable声明为超级接口.相反,请参阅the JavaDoc page for AutoCloseable以获取所有捆绑子接口和实现类的列表(实际上是几十个).例如,对于SQL工作,我们看到Connection,Statement,PreparedStatement,ResultSet和RowSet都可以自动关闭,但DataSource不是.

请参见Oracle教程,The try-with-resources Statement.

代码示例

您的上一个代码示例接近良好,但应该在try-with-resources语句中包装ResultSet以自动关闭.

引用ResultSet JavaDoc:

A ResultSet object is automatically closed when the Statement object that generated it is closed, re-executed, or used to retrieve the next result from a sequence of multiple results.

正如您的老师一直建议的那样,某些JDBC驱动程序存在严重缺陷,这些缺陷未能达到JDBC规范在Statement或PreparedStatement关闭时关闭ResultSet的承诺.许多程序员习惯于显式关闭每个ResultSet对象.

现在使用try-with-resources语法可以更轻松地完成这项额外任务.在实际工作中,您可能会尝试使用所有AutoCloseable对象(例如ResultSet).所以我自己的观点是:为什么不把它作为资源尝试呢?没有伤害,使您的代码更自我记录您的意图,如果您的代码遇到其中一个错误的JDBC驱动程序,它可能会有所帮助.唯一的成本是一对parens,假设你有一个尝试捕获 – 否则就位.

Oracle Tutorial所述,一起声明的多个AutoCloseable对象将以相反的顺序关闭.

提示:try-with-resources语法允许在最后声明的资源项上使用可选分号.我将分号作为习惯包括在内,因为它能很好地读取,并且是一致的,并且有助于剪切和粘贴编辑.我将它包含在您的PreparedStatement s2行中.

public void doQueries() throws MyException{
    // First try-with-resources.
    try ( Connection con = DriverManager.getConnection( dataSource ) ;
          PreparedStatement s1 = con.prepareStatement( updateSqlQuery ) ;
          PreparedStatement s2 = con.prepareStatement( selectSqlQuery ) ;
    ) {

        … Set parameters of PreparedStatements, etc.

        s1.executeUpdate() ;

        // Second try-with-resources, nested within first.
        try (
            ResultSet rs = s2.executeQuery() ;
        ) {
            … process ResultSet
        } catch ( SQLException e2 ) {  
            … handle exception related to ResultSet.
        }

    } catch ( SQLException e ) {  
        … handle exception related to Connection or PreparedStatements.
    }
}

我想这种工作有一种更优雅的语法,可能是在未来的编程语言中发明的.但是现在,我们已经尝试了资源,我确实很愉快地使用它.虽然try-with-resources并不是非常优雅,但它比旧语法有了很大的改进.

顺便说一下,Oracle建议使用DataSource实现来获取连接,而不是代码中看到的DriverManager方法.在整个代码中使用DataSource可以更轻松地切换驱动程序或切换到连接池.查看JDBC驱动程序是否提供DataSource的实现.

更新:Java 9

现在,在Java 9中,您可以在try-with-resources之前初始化资源.见this article.

标签:correctness,java,try-with-resources
来源: https://codeday.me/bug/20191001/1840554.html