简体   繁体   中英

MySql too many connections

I hate to bring up a question which is widely asked on the web, but I cant seem to solve it.

I started a project a while back and after a month of testing, I hit a "Too many connections" error. I looked into it, and "Solved" it by increasing the max_connections. This then worked.

Since then more and more people started to use it, and it hit again. When I am the only user on the site, i type "show processlist" and it comes up with about 50 connections which are still open (saying "Sleep" in the command). Now, I dont know enough to speculate why these are open, but in my code I tripple checked and every connection I open, I close.

ie.

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

Every time I do something else on the site, another load of connections are opened and not closed. Is there something wrong with my code? and if not, what could be the problem?

With your approach, the connection will never be closed if any exception is been thrown before the conn.close() is called. You need to acquire it (and the statement and resultset) in a try block and close it in the finally block. Any code in finally will always be executed regardless of an exception is been thrown or not. With this you can ensure that the expensive resources will be closed.

Here's a rewrite:

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

That said, this code is sensitive to SQL injection attacks . Use a PreparedStatement instead of Statement .

See also :

One possible flow in which this code can leak connection is:

  1. Stmt.executeQuery() results empty resultset
  2. You do not check whether rs.next() returns true or false
  3. rs.getInt("id") throws exception as there is not current row in resultset
  4. conn.close() is skipped

Do the following:

  1. Make rs.getInt() conditional on rs.next()
  2. Close the connection in finally block and do all the data access within try block

Edit:

Also it's a good idea to log all exceptions somewhere so that you have a good starting point in your troubleshooting.

If the code throws a DataAccessException or java.sql.SQLException the connection will not be closed resulting in many open sleeping connections ;) Make a try-finally-Block which will close the connection.

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

It's a trivial example but a little more complex because you have to check wich of these objects are really created and used.

The temporary solution for this problem can be increasing the allowed maximum connections of the mysql.You can do this by the below mentioned either of the two ways.

First:

Login into the mysql server and type the below given command.

mysql> SET GLOBAL max_connections = 200;

This will increase the maximum connections.But this setting will change if the server is restarted.

Second:

Edit the file /etc/mysql/my.cnf and increase the max_connection in this file.

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

max_connections = 100

Save the changes and type the following to restart mysqld:

/etc/init.d/mysqld restart

But this problem , usually appears because of the open connections that are not properly close and are unavailable to use.

Just try looking into all of the resources that are accessing your data base and check if all the connections are properly handled.

looking into the code it can be seen that you have not placed the code in the try and catch.

According to your code , if the exception occurs in fetching the data your connection will not be closed and hence it will be a waste of resource.Hence as the coding standard suggests use the try and catch with finally to handle the connections.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM