Модераторы: LSD, AntonSaburov
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Пул коннектов к MySQL - разрыв соединений, CommunicationsException  
:(
    Опции темы
neonfly
Дата 22.10.2009, 10:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 7
Регистрация: 31.8.2009

Репутация: нет
Всего: нет



Код

import java.util.ArrayList;
import java.util.List;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.DriverManager;

public class DatabasePool {
    private final String DRIVER = "com.mysql.jdbc.Driver";
    private final String URL = "jdbc:mysql://127.0.0.1:3306/testbase";
    private final String USER = "root";
    private final String PASSWORD = "root";
    private static int max = 10;     // default

    private static DatabasePool instance;
    private List<PoolItem> connections = new ArrayList<PoolItem>();

    public static void setPoolSize(int size) {
        max = size;
    }   

    private DatabasePool() throws SQLException, ClassNotFoundException {
        Class.forName(DRIVER);
        for (int i = 0; i < max; i++) {
            connections.add(createPoolItem());
        }
    }

    static public DatabasePool getInstance() {
        if (instance == null) {
            try {
                instance = new DatabasePool();
            } catch (SQLException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();  
            }
        }
        return instance;
    }

    public synchronized Connection getConnection() throws SQLException {
        for (PoolItem item : connections) {
            if (item.free) {
                item.free = false;
                return item.connection;
            }
        }

        PoolItem poolItem = createPoolItem();
        connections.add(poolItem);
        poolItem.free = false;
        return poolItem.connection;
    }

    public synchronized void closeConnection(Connection connection) {
        for (PoolItem item : connections) {
            if (item.connection == connection) {
                item.free = true;
                return;
            }
        }
    }

    private PoolItem createPoolItem() throws SQLException {
        return new PoolItem(DriverManager.getConnection(URL, USER, PASSWORD));
    }

    private class PoolItem {
        private Connection connection;
        private boolean free;

        public PoolItem(Connection connection) {
            free = true;
            this.connection = connection;
        }
    }
}


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

Код

com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
Last packet sent to the server was 47 ms ago.
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
        at com.mysql.jdbc.Util.handleNewInstance(Util.java:406)
        at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:1074)
        at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3009)
        at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:2895)
        at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3438)
        at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1951)
        at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2101)
        ...................


В чем может быть проблема? Кто сталкивался или у кого какие мысли?



Это сообщение отредактировал(а) neonfly - 22.10.2009, 16:09
PM MAIL ICQ Skype   Вверх
dementiev
Дата 22.10.2009, 16:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 114
Регистрация: 8.2.2008
Где: Минск

Репутация: нет
Всего: 1



без пулла всё работает?
PM MAIL   Вверх
ivanovpv
Дата 22.10.2009, 16:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Варвар
**


Профиль
Группа: Участник
Сообщений: 639
Регистрация: 26.1.2005
Где: Москва

Репутация: 4
Всего: 28



Если честно - какой то странный у вас пул... Вы сразу открываете все соединения, никогда и нигде их не разрываете (по крайней мере я этого не увидел). Когда вам нужно вы берете из списка первый неиспользуемый коннект. Нет никакой гарантии, что сервер к моменту обращения за соединением (скажем через несколько часов) - не сбросил соединение.

Если уж так охота создать свой пул (хотя пакетов для этого туча) - я бы написал пул так:
1) Создаем некую обертку вокруг Connection а ля PooledConnection
2) Далее пишем обертку вокруг всех вызовов JDBC использующих Connection, так чтобы они использовали мой PooledConnection
3) PooledConnection реализуем так:
    а) Реальное соединение с БД открываем только тогда когда происходит вызов сервера
    б) При вызове сервера - фиксируем currenttimemillis
4) Теперь создаем PoolOfPooledConnections, который держит список PooledConnection и имеет внутренний поток, который обходит все PooledConnection и если они давно не использовались закрывает их
5) При запросе соединения из пула - ищем соединение которое использовалось последним опираясь на currenttimemillis прописанный внутри каждого экземпляра PooledConnection

Почитайте про пулы JDBC соединений, JDBC 3 (а может и даже 2) уже имеет некий API для написания пулов и они активно используются многими серверами. Тот же JDBC драйвер мускула имеет свой пул.


--------------------
Aut viam inveniam aut faciam
PM MAIL Skype   Вверх
tux
Дата 22.10.2009, 16:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Летатель
***


Профиль
Группа: Участник Клуба
Сообщений: 1853
Регистрация: 10.2.2005
Где: msk.ru

Репутация: 31
Всего: 132



Это известная проблема разрыва соединений сервером MySQL, на этоv форуме обсуждалась многократно. Вариант решения такой - для каждого неактивного соединения по таймауту выполнять какой-то простой запрос, например, 'select 1' через определенное время (положим, один раз в час). Это сбрасывает таймаут на сервере. Еще неплохо было бы проверять не закрыто ли соединение прежде чем выдавать его пользователю - метод isClosed() у соединения и переоткрывать если закрыто.
PM MAIL Skype GTalk Jabber YIM   Вверх
neonfly
Дата 22.10.2009, 17:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 7
Регистрация: 31.8.2009

Репутация: нет
Всего: нет



Спасибо за исчерпывающие ответы!

Буду делать так:
1. В каждом PoolItem введу переменную - время последнего использования.
2. Периодически в новом потоке буду проверять, не больше ли переменная, скажем, одному часу. 
3. Следовательно, если больше, буду закрывать соединение.
И так до конца. Т.е. может возникнуть ситуация что все соединения будут закрыты. Тогда, при очередном вызове, буду создавать новый коннекшн к базе.

ПС. Не хочу использовать сторонние пулы. Нет четкого контроля над ними.

PM MAIL ICQ Skype   Вверх
neonfly
Дата 23.10.2009, 09:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 7
Регистрация: 31.8.2009

Репутация: нет
Всего: нет



Написал такой класс, который будет выполняться каждый час.

Код
private class CheckPool extends Thread {
    public void run() {
        while (true) {
            try {
                // каждый час выполнять эту функцию
                Thread.sleep(60 * 60 * 1000);  // на 1 час
                for (PoolItem item : connections) {
                    Long t1 = item.timeout;
                    Long t2 = System.nanoTime();
                    if ((t2 - t1) / 1000000000 > 3600) {
                        item.setLocked(true);
                        
                        Statement stm =  item.connection.createStatement();
                        stm.execute("SELECT 1");
                        stm.close();  
                        
                        item.setLocked(false);
                        item.timeout = t2;
                    }
                }  
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}




Это сообщение отредактировал(а) neonfly - 23.10.2009, 09:57
PM MAIL ICQ Skype   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
javastic
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux, javastic.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0729 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.