MySql连接太多了

时间:2010-06-18 12:03:41

标签: java mysql tomcat jdbc

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

我在一段时间后开始了一个项目,经过一个月的测试后,我遇到了“Too many connections”错误。我调查了它,并通过增加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;
}

每次我在网站上执行其他操作时,都会打开另一个连接并且不会关闭。 我的代码有问题吗?如果不是,那可能是什么问题?

4 个答案:

答案 0 :(得分:11)

使用您的方法,如果在调用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

另见

答案 1 :(得分:2)

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

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

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

      修改

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

答案 2 :(得分:0)

如果代码抛出DataAccessException或java.sql.SQLException,则连接将不会关闭,导致许多打开的睡眠连接;) 制作一个try-finally-Block,它将关闭连接。

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

这是一个微不足道的例子,但有点复杂,因为你必须检查这些对象是否真正被创造和使用。

答案 3 :(得分:0)

此问题的临时解决方案可以增加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和catch中。

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

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();
        }
    }