MySql слишком много соединений - PullRequest
3 голосов
/ 18 июня 2010

Я не хочу поднимать вопрос, который часто задают в Интернете, но, похоже, я не могу его решить.

Я начал проект некоторое время назад, и после месяца тестирования, я столкнулся с ошибкой "Слишком много подключений". Я посмотрел на это и «решил», увеличив 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 ]

11 голосов
/ 18 июня 2010

При вашем подходе соединение никогда не будет закрыто, если какое-либо исключение было выдано до того, как будет вызван 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инъекция атака .Используйте PreparedStatement вместо Statement.

См. Также :

2 голосов
/ 18 июня 2010

Один из возможных потоков, в котором этот код может пропустить соединение:

  1. Stmt.executeQuery () приводит к пустому результирующему набору
  2. Вы не проверяете, возвращает ли rs.next () значение trueили false
  3. rs.getInt ("id") выдает исключение, поскольку в наборе результатов нет текущей строки
  4. conn.close () пропущено

Выполнитеследующее:

  1. Сделайте rs.getInt () условным для rs.next ()
  2. Закройте соединение в блоке finally и выполните весь доступ к данным в блоке try

Редактировать:

Также рекомендуется записывать все исключения где-нибудь, чтобы у вас была хорошая отправная точка для устранения неполадок.

0 голосов
/ 13 января 2017

Временным решением этой проблемы может быть увеличение максимально допустимых подключений 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 с 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();
        }
    }
0 голосов
/ 18 июня 2010

Если код выдает исключение DataAccessException или java.sql.SQLException, соединение не будет закрыто, что приведет к множеству открытых спящих соединений;) Создайте блок try-finally, который закроет соединение.

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

Это тривиальный пример, но немного более сложный, потому что вы должны проверить, какие из этих объектов действительно созданы и используются.

...