【问题标题】:Connection to SqlServer not closing in for loop java与 SqlServer 的连接未关闭 for 循环 java
【发布时间】:2017-09-13 10:02:34
【问题描述】:

我不确定这方面的最佳做法,但我的总体问题是我无法弄清楚为什么我的连接没有关闭。

我基本上是在遍历一个列表,然后将它们插入到一个表中。在将它们插入表格之前,我会检查并确保它不是重复的。如果是,我更新行而不是插入它。截至目前,在调试让我知道我的连接未关闭之前,我只能进行 13 次迭代。

由于我有 2 个连接,我无法确定我应该在哪里关闭我的连接,我试图使用其他示例来提供帮助。这是我得到的:

        Connection con = null;
    PreparedStatement stmt = null;
    PreparedStatement stmt2 = null;
    ResultSet rs = null;
    Connection con2 = null;


    for (Object itemId: aList.getItemIds()){
        try {
            con = cpds2.getConnection();
                stmt = con.prepareStatement("select [ID] from [DB].[dbo].[Table1] WHERE [ID] = ?");
                stmt.setInt(1, aList.getItem(itemId).getBean().getID());

                rs = stmt.executeQuery();
            //if the row is already there, update the data/

                if (rs.isBeforeFirst()){
                    System.out.println("Duplicate");
                    stmt2 = con2.prepareStatement("UPDATE [DB].[dbo].[Table1] SET "
                    + "[DateSelected]=GETDATE() where  [ID] = ?");
                    stmt2.setInt(1,aList.getItem(itemId).getBean().getID());
                stmt2.executeUpdate();
                }//end if inserting duplicate
                else{
                    con2 = cpds2.getConnection();
                    System.out.println("Insertion");
                    stmt.setInt(1, aList.getItem(itemId).getBean().getID());

                    //Otherwise, insert them as if they were new
                    stmt2 = con.prepareStatement("INSERT INTO [DB].[dbo].[Table1] ([ID],[FirstName],"
                            + "[LastName],[DateSelected]) VALUES (?,?,?,?)");
                    stmt2.setInt(1,aList.getItem(itemId).getBean().getID() );
                    stmt2.setString(2,aList.getItem(itemId).getBean().getFirstName());
                    stmt2.setString(3,aList.getItem(itemId).getBean().getLastName() );
                    stmt2.setTimestamp(4, new Timestamp(new Date().getTime()));
                    stmt2.executeUpdate();
                }//End Else
        }catch(Exception e){
                e.printStackTrace();
            }//End Catch
        finally{
                try { if (rs!=null) rs.close();} catch (Exception e) {}
            try { if (stmt2!=null) stmt2.close();} catch (Exception e) {}
            try { if (stmt!=null) stmt.close();} catch (Exception e) {}
            try { if (con2!=null) con2.close();} catch (Exception e) {}
            try {if (con!=null) con.close();} catch (Exception e) {}
            }//End Finally

    } //end for loop
    Notification.show("Save Complete");

这是我的池连接:

    //Pooled connection
    cpds2 = new ComboPooledDataSource();

    try {
        cpds2.setDriverClass("net.sourceforge.jtds.jdbc.Driver");
    } catch (PropertyVetoException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } //loads the jdbc driver
    cpds2.setJdbcUrl( "jdbc:jtds:sqlserver://SERVERNAME;instance=DB" );
    cpds2.setUser("username");
    cpds2.setPassword("password"); 
    cpds2.setMaxStatements( 180 ); 
    cpds2.setDebugUnreturnedConnectionStackTraces(true); //To help debug
    cpds2.setUnreturnedConnectionTimeout(2);  //to help debug

我的主要问题是,我关闭我的连接对吗?我的连接池设置正确吗? 我应该在 for 循环内部还是外部关闭连接?

c3p0 有问题吗?还是 JTDS?

【问题讨论】:

  • 恕我直言,您应该在for 循环之外建立连接,然后在循环完成/退出时关闭。否则,您将在每个循环中获得一个新连接。是的,池化得到了缓解,但仍然可以避免很多流失。
  • 很抱歉,这听起来像是一个非常愚蠢的问题,但是在同一个连接关闭之前多次重复使用准备好的语句是否安全?
  • 是的。您甚至可以在循环外准备语句,并在每次迭代时更新参数。此外,除非您连接到两个不同的数据源(而且它看起来不像您),否则您可以删除con2 并使用con 处理所有内容。可能是微优化,但如果你经常循环这个,它就会加起来。

标签: java sql-server c3p0 jtds


【解决方案1】:

很高兴您能够小心谨慎地close() 您的资源,但这太复杂了。

除非您使用的是相当旧的 Java 版本(Java 7 之前的版本),否则您可以使用 try-with-resources,这确实简化了这些工作。在一个逻辑工作单元中使用两个不同的连接会引起误解。资源应尽可能在本地使用close()ed,而不是将所有内容推迟到最后。

您的异常处理很危险。如果发生您不理解的异常,您可能想要打印其堆栈跟踪,但您的代码应该表明您所做的任何事情都不起作用的事实。你吞下了异常,甚至通知“保存完成”。

综上所述,MERGE 声明(I think SQL Server supports)可能会让您的生活变得更轻松。

这是一个(未经测试、未编译的)示例重组:

try ( Connection con = cpds2.getConnection() ) {
    for (Object itemId: aList.getItemIds()){
        boolean id_is_present = false;
        try ( PreparedStatement stmt = con.prepareStatement("select [ID] from [DB].[dbo].[Table1] WHERE [ID] = ?") ) {
            stmt.setInt(1, aList.getItem(itemId).getBean().getID());
            try ( ResultSet rs = stmt.executeQuery() ) {
               id_is_present = rs.next();
            }
        }
        if ( id_is_present ) {
            System.out.println("Duplicate");
            try ( PreparedStatement stmt = con.prepareStatement("UPDATE [DB].[dbo].[Table1] SET [DateSelected]=GETDATE() where  [ID] = ?") ) {
                stmt.setInt(1,aList.getItem(itemId).getBean().getID());
                stmt.executeUpdate();
            }
         } else {
             System.out.println("Insertion");
             try ( PreparedStatement stmt = con.prepareStatement("INSERT INTO [DB].[dbo].[Table1] ([ID],[FirstName], [LastName],[DateSelected]) VALUES (?,?,?,?)") ) {
                 stmt.setInt(1,aList.getItem(itemId).getBean().getID() );
                 stmt.setString(2,aList.getItem(itemId).getBean().getFirstName());
                 stmt.setString(3,aList.getItem(itemId).getBean().getLastName() );
                 stmt.setTimestamp(4, new Timestamp(new Date().getTime()));
                 stmt.executeUpdate();
             }
         }
    }
    Notification.show("Save Complete");    
}    

【讨论】:

  • 好的,我在程序中重写了我的连接,以尝试使用资源,似乎连接正在关闭。我真的很惊讶,当我查找使用 sql 创建连接的示例时,我从未在其中找到尝试使用资源。它总是尝试/捕捉/最终。谢谢你的回答。
猜你喜欢
  • 2021-02-20
  • 2019-08-12
  • 2016-03-25
  • 2017-02-19
  • 1970-01-01
  • 2020-02-02
  • 1970-01-01
  • 1970-01-01
  • 2013-01-11
相关资源
最近更新 更多