我讨厌提出一个在网络上广泛提出的问题,但我似乎无法解决它。
我在一段时间后开始了一个项目,经过一个月的测试后,我遇到了“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;
}
每次我在网站上执行其他操作时,都会打开另一个连接并且不会关闭。 我的代码有问题吗?如果不是,那可能是什么问题?
答案 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)
此代码可能泄漏连接的一个可能流程是:
执行以下操作:
修改强>
最好在某处记录所有异常,以便在故障排除中有一个良好的起点。
答案 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();
}
}