2010-06-18 5 views
3

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

Я начал проект некоторое время назад, и после месяца тестирования я ударил ошибку «Слишком много соединений». Я просмотрел его и «решил», увеличив max_connections. Тогда это сработало.

С тех пор все больше и больше людей начали использовать его, и он снова ударил. Когда я являюсь единственным пользователем на сайте, я набираю «show processlist», и в нем появляется около 50 подключений, которые все еще открыты (говорят «Сон» в команде). Теперь я не знаю достаточно, чтобы предположить, почему они открыты, но в моем коде я проверил трижды и каждое открытое соединение закрываю.

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

Каждый раз, когда я делаю что-то еще на сайте, открыта и не закрыта другая нагрузка соединений. Что-то не так с моим кодом? и если нет, то в чем проблема?

+0

Что это такое.getSession(). Connection() делать? –

+0

И это единственное место в вашем приложении, что вы открываете соединения? –

+0

Вы регистрируете все исключения где-то? –

ответ

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

2

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

  1. Stmt.executeQuery() Результаты пуст Resultset
  2. Вы не проверить, возвращает ли rs.next() истинный или ложный
  3. Rs.GetInt ("ID") бросает исключение, поскольку нет текущей строки в результирующем
  4. conn.Close() пропускается

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

  1. Сделать rs.getInt() обусловливающие rs.next()
  2. Закройте соединение в конце концов блокировать и делать весь доступ к данным внутри блока Ьги

Edit:

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

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 

Сохраните изменения и введите следующую команду, чтобы перезапустить туздЫ:

/etc/init.d/mysqld restart 

Но эта проблема, как правило, появляется из-за открытых соединений, которые не должным образом закрыть и недоступны для использования.

Просто попробуйте изучить все ресурсы, которые обращаются к вашей базе данных, и проверьте, правильно ли обработаны все соединения.

глядя в код, видно, что вы не поставили код в 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(); 
     } 
    }