JDBC 连接过多 - 连接正确关闭

Posted

技术标签:

【中文标题】JDBC 连接过多 - 连接正确关闭【英文标题】:JDBC too many connections - Connections are closed properly 【发布时间】:2014-12-24 21:24:38 【问题描述】:

我讨厌提出一个在网络上被广泛询问的问题,但我似乎无法解决它。 我正在正确关闭所有连接,但程序抛出“连接异常过多”

这是我的连接助手

 public mysqlConnection() 
    try 

      // Datenbanktreiber für ODBC Schnittstellen laden.
      // Für verschiedene ODBC-Datenbanken muss dieser Treiber
      // nur einmal geladen werden.
      Class.forName("com.mysql.jdbc.Driver");

      // Verbindung zur ODBC-Datenbank 'sakila' herstellen.
      // Es wird die JDBC-ODBC-Brücke verwendet.
      conn = DriverManager.getConnection("jdbc:mysql://" + dbHost + ":"
          + dbPort + "/" + database + "?" + "user=" + dbUser + "&"
          + "password=" + dbPassword);
     catch (ClassNotFoundException e) 
      System.out.println("Treiber nicht gefunden");
     catch (SQLException e) 
      System.out.println("Connect nicht moeglich"+e);
    
  

  public Connection getInstance()
  

    if(conn == null)
      new MySQLConnection();
    return conn;
  


  public final void close_multiple( final Connection con, final ArrayList<PreparedStatement> listPreparedstatments, final ArrayList<ResultSet> listResultsets )
  
      try
      
          if ( con != null && con.isClosed())
          
              con.close();

          
          for(PreparedStatement pstm : listPreparedstatments)
              if ( pstm != null && pstm.isClosed())
              
                  pstm.close();
              
          for(ResultSet rs : listResultsets)
              if ( rs != null && rs.isClosed())
              
                  rs.close();
              
          

      
      catch ( SQLException e )
      
          e.printStackTrace();
      
  

  public final void close_single( final Connection con, final PreparedStatement stmt, final ResultSet rs )
  
      try
      
          if( con != null && con.isClosed())
          
              con.close();
          
          if ( stmt != null && stmt.isClosed())
          
              stmt.close();
          
          if ( rs != null && rs.isClosed())
          

            rs.close();
          

      
      catch ( SQLException e )
      
          e.printStackTrace();
      
  

这里有一些示例代码

 public ArrayList<Product_Type> getProduct_Types() throws JSONException 
      conn = mysqlconnection.getInstance();
      Product_Type product_type;
      ArrayList<Product_Type> listProduct_Types = new ArrayList<Product_Type>();
      if(conn != null)
          //MYSQL Resultsets and Statements
          ResultSet rst_product_type=null;
          PreparedStatement pstmt_product_type=null;
          try

            String sql = "SELECT * FROM `product_type`";
            pstmt_product_type = conn.prepareStatement(sql);
            rst_product_type = pstmt_product_type.executeQuery();

            while(rst_product_type.next())  
                product_type = new Product_Type();
                product_type.setProduct_Type_ID(rst_product_type.getInt("Product_Type_ID"));
                product_type.setProduct_Type_Name(rst_product_type.getString("Product_Type_Name")); 
                listProduct_Types.add(product_type);
            
          catch(Exception e)
            System.out.println("Unable to connect to product_type Table.");
          finally 
             mysqlconnection.close_single(conn, pstmt_product_type, rst_product_type);
         
      
      return listProduct_Types; 
  

  public ArrayList<Product_Type> getProduct_Type_by_Manufacturer_ID(int manufacturer_id) throws JSONException, SQLException 
        conn = mysqlconnection.getInstance();
        Product_Type product_type;
        ArrayList<Product_Type> listProduct_Types = new ArrayList<Product_Type>();
        ArrayList<ResultSet> listResultsets = new ArrayList<ResultSet>();
        ArrayList<PreparedStatement> listPreparedstatments = new ArrayList<PreparedStatement>();

         if(conn != null)
             PreparedStatement pstmt_product_detail = null;
             PreparedStatement pstmt_product_type = null;

             ResultSet rst_product_type = null;
             ResultSet rst_product_detail = null;
             try                       
                    String sql_product_detail = "SELECT DISTINCT(Product_Type_ID) FROM `product_details` WHERE Manufacturer_ID=?"; 
                    pstmt_product_detail = conn.prepareStatement(sql_product_detail);
                    pstmt_product_detail.setInt(1, manufacturer_id);
                    rst_product_detail = pstmt_product_detail.executeQuery();

                    while(rst_product_detail.next())  
                         String sql_product_type = "SELECT Product_Type_ID, Product_Type_Name FROM `product_type` WHERE Product_Type_ID=?";
                         pstmt_product_type = conn.prepareStatement(sql_product_type);
                         pstmt_product_type.setInt(1, rst_product_detail.getInt("Product_Type_ID"));
                         rst_product_type = pstmt_product_type.executeQuery();

                         while(rst_product_type.next())  
                             product_type = new Product_Type();
                             product_type.setProduct_Type_ID(rst_product_type.getInt("Product_Type_ID"));
                             product_type.setProduct_Type_Name(rst_product_type.getString("Product_Type_Name"));    
                             listProduct_Types.add(product_type);
                        
                     
                    listPreparedstatments.add(pstmt_product_type);
                    listPreparedstatments.add(pstmt_product_detail);
                    listResultsets.add(rst_product_detail);
                    listResultsets.add(rst_product_type);
              catch(Exception e)
                System.out.println("Unable to connect to pr Table.");
              finally 
                 //Close MYSQL-Connection
                 mysqlconnection.close_multiple(conn, listPreparedstatments, listResultsets);
             
         

         return listProduct_Types;
  

我不明白问题出在哪里?我也尝试增加 mysql 最大连接数,但它仍然无法正常工作

【问题讨论】:

除此之外,你为什么要在 instance 方法中创建MySQLConnection() 的新实例...你为什么不直接在那里创建连接呢?我假设conn 是一个静态变量,虽然你没有展示它......这真的很乱。 (而且你的名字不遵循 Java 命名约定......) 是的,感谢您的评论。我改了好几次代码,所以有点乱,但我会改变你提到的点 另外...您不需要继续检查连接...将连接移到 try 块中,然后在完成后将其关闭。 你最好还是使用driver manager 来处理连接。 自 2007 年以来,您不再需要 Class.forName() 电话。 【参考方案1】:

您实际上根本没有关闭连接(以及 ResultSets 和 PreparedStatements),只有在连接已经关闭时才会调用此代码中的 con.close()

if (con != null && con.isClosed()) 
    con.close();

应该是!con.isClosed()

这似乎是主要问题。但是,正如 John Skeet 在问题评论中提到的那样,您的代码中还存在其他问题。

【讨论】:

同一点也适用于其他 if 条件,对于 PreparedStatements 和 ResultSets。我还认为您可能希望在关闭连接之前关闭这些东西。【参考方案2】:

从 Java7 开始,您可以利用 try-with-resource 自动关闭资源(资源是在程序完成后必须关闭的对象)。此外,您的代码将被简化(通过删除您只是检查和关闭连接、语句、结果集的行),易于阅读和维护例如

try (Connection conn = datasource.getConnection();
    Statement stmt = conn.createStatement()) // you can use all other autocloseable objects in try clause

 //your code here
 

【讨论】:

give u plus 提及尝试资源

以上是关于JDBC 连接过多 - 连接正确关闭的主要内容,如果未能解决你的问题,请参考以下文章

使用 JDBC 获取与 MySQL 的连接时出现“连接过多”

如何记录 Tomcat 7 JDBC 连接池、连接创建

ExecutorService 导致 JDBC 连接问题

java程序访问数据库,dbcp连接池,hibernate连接总是报池连接用光了/JDBC连接没有报错

mysql 数据库中出现1040问题是怎么回事,在连接数据库的时候我写了关闭链接的,怎么还是会说链接过多

Redshift 连接未以正确方式关闭