【问题标题】:MySql too many connectionsMySql 连接太多
【发布时间】:2011-03-05 09:43:56
【问题描述】:

我讨厌提出一个在网络上被广泛询问的问题,但我似乎无法解决。

我不久前开始了一个项目,经过一个月的测试,我遇到了“连接太多”错误。我调查了它,并通过增加 max_connections 来“解决”它。然后就奏效了。

从那以后,越来越多的人开始使用它,并且它再次流行起来。当我是站点上的唯一用户时,我键入“show processlist”,它会提供大约 50 个仍然打开的连接(在命令中说“Sleep”)。现在,我不知道为什么要推测这些是打开的,但是在我的代码中,我检查了三次,并且我打开的每个连接都关闭了。

即。

public int getSiteIdFromName(String name, String company)throws DataAccessException,java.sql.SQLException{

Connection conn = this.getSession().connection();
Statement smt = conn.createStatement();
ResultSet rs=null;
String query="SELECT id FROM site WHERE name='"+name+"' and company_id='"+company+"'";

rs=smt.executeQuery(query);
rs.next();

int id=rs.getInt("id");

rs.close();
smt.close();
conn.close();
return id;
}

每次我在网站上做其他事情时,都会打开而不是关闭另一批连接。 我的代码有问题吗?如果不是,可能是什么问题?

【问题讨论】:

  • this.getSession().connection() 在做什么?
  • 这是您应用中唯一打开连接的地方吗?
  • 您是否在某处记录所有异常?

标签: java mysql tomcat jdbc


【解决方案1】:

如果代码抛出 DataAccessException 或 java.sql.SQLException 连接将不会关闭,从而导致许多打开的休眠连接;) 做一个 try-finally-Block 来关闭连接。

Connection conn = this.getSession().connection();
try {
  // all code
} finally {
  rs.close();
  smt.close();
  conn.close();
}

这是一个简单的例子,但有点复杂,因为您必须检查这些对象中的哪些是真正创建和使用的。

【讨论】:

    【解决方案2】:

    使用您的方法,如果在调用conn.close() 之前抛出任何异常,连接将永远不会关闭。您需要在try 块中获取它(以及语句和结果集)并在finally 块中关闭它。无论是否引发异常,finally 中的任何代码都将始终执行。这样,您可以确保关闭昂贵的资源。

    这里是重写:

    public int getSiteIdFromName(String name, String company) throws DataAccessException, java.sql.SQLException {
        Connection conn = null;
        Statement smt = null;
        ResultSet rs = null;
        int id = 0;
        try {
            conn = this.getSession().connection();
            smt = conn.createStatement();
            String query = "SELECT id FROM site WHERE name='" + name + "' and company_id='" + company + "'";
            rs = smt.executeQuery(query);
            rs.next();
            id = rs.getInt("id");
        } finally {
            if (rs != null) try { rs.close(); } catch (SQLException logOrIgnore) {}
            if (smt != null) try { smt.close(); } catch (SQLException logOrIgnore) {}
            if (conn != null) try { conn.close(); } catch (SQLException logOrIgnore) {}
        }
        return id;
    }
    

    也就是说,此代码对SQL injection attacks 敏感。使用PreparedStatement 而不是Statement

    另见

    【讨论】:

    • 另一个信息性和描述性的答案 BalusC,谢谢。我会在网站上试一试,看看它是否能解决问题
    【解决方案3】:

    此代码可能泄漏连接的一个可能流程是:

    1. Stmt.executeQuery() 结果为空结果集
    2. 您不检查 rs.next() 是返回 true 还是 false
    3. rs.getInt("id") 抛出异常,因为结果集中没有当前行
    4. conn.close() 被跳过

    执行以下操作:

    1. 使 rs.getInt() 以 rs.next() 为条件
    2. 在 finally 块中关闭连接并在 try 块中进行所有数据访问

    编辑:

    此外,最好在某处记录所有异常,以便您在故障排除时有一个良好的起点。

    【讨论】:

      【解决方案4】:

      这个问题的临时解决办法是增加mysql允许的最大连接数。你可以通过下面提到的两种方式来做到这一点。

      第一:

      登录到mysql服务器并输入以下给定的命令。

      mysql> SET GLOBAL max_connections = 200;
      

      这将增加最大连接数。但如果服务器重新启动,此设置会改变。

      第二:

      编辑文件/etc/mysql/my.cnf,增加该文件中的max_connection。

      [mysqld]
      local-infile=0
      datadir=/var/lib/mysql
      user=mysql
      symbolic-links=0
      
      max_connections = 100
      

      保存更改并键入以下内容以重新启动 mysqld:

      /etc/init.d/mysqld restart
      

      但是这个问题,通常是因为打开的连接没有正确关闭,无法使用。

      只需尝试查看所有正在访问您的数据库的资源,并检查所有连接是否都得到了正确处理。

      查看代码可以看出您没有将代码放入try and catch中。

      根据您的代码,如果在获取数据时发生异常,您的连接将不会关闭,因此会浪费资源。因此,正如编码标准所建议的那样,使用 try 和 catch 和 finally 来处理连接。

      try{
      //your code 
      }
      catch(Exception e){
      
      //handle the exceptions here
      }
      
      finally{
              try{
                  channel.close();
              } catch(Exception e){
                  log.error("Error is "+e.getMessage(),e);
                  e.printStackTrace();
              }
              try {
                  connection.close();
              } catch (IOException e) {
                  log.error("Error is "+e.getMessage(),e);
                  // TODO Auto-generated catch block
                  e.printStackTrace();
              }
              catch(Exception e){
                  log.error("Error is "+e.getMessage(),e);
                  e.printStackTrace();
              }
          }
      

      【讨论】:

        猜你喜欢
        • 2017-12-27
        • 1970-01-01
        • 1970-01-01
        • 2013-01-13
        • 1970-01-01
        • 2010-11-15
        • 2020-01-24
        • 2017-10-29
        • 2014-09-08
        相关资源
        最近更新 更多