2010-06-18 116 views
3

我讨厌提出一个在网上被广泛询问的问题,但我似乎无法解决它。MySql连接太多

我刚开始一个项目,经过一个月的测试,我遇到了“连接太多”的错误。我看着它,并通过增加max_connections来“解决”它。然后这工作。

从那时起,越来越多的人开始使用它,并且它再次出现。当我是网站上的唯一用户时,我输入“show processlist”,然后出现大约50个仍处于打开状态的连接(在命令中说“睡眠”)。现在,我不知道足以推测为什么这些是开放的,但在我的代码中,我反复检查并打开每个连接,我关闭。

即。

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

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

+0

什么是this.getSession().connection()在做什么? – 2010-06-18 12:11:09

+0

而且这是你的应用程序中您打开连接的唯一地方吗? – 2010-06-18 12:12:35

+0

您是否在某处记录所有异常? – 2010-06-18 12:13:06

回答

0

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

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

这是一个简单的例子,却多了几分复杂,因为你必须检查这些对象至极真正创建和使用。

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 injectionattacks敏感。使用PreparedStatement而不是Statement

参见:

+1

BalusC的另一个内容丰富和描述性的答案,谢谢。我会给它通过网站,看看它是否能解决问题 – MichaelMcCabe 2010-06-18 12:31:45

2

一种可能的流,其中该代码可以泄漏连接是:

  1. Stmt.executeQuery()会导致空结果
  2. 你不检查rs.next()是否返回true或false
  3. RS。getInt( “ID”)抛出异常,因为没有当前行中的ResultSet
  4. conn.close()被跳过

执行以下操作:

  1. 让rs.getInt()有条件的rs.next()
  2. 关闭在最后的连接块,做try块内的所有数据访问

编辑:

此外,记录所有异常情况是一个好主意,这样您在排除故障时就有了一个很好的起点。

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