JDBC MySql практики пулов соединений, чтобы избежать исчерпания пула соединений - PullRequest
10 голосов
/ 22 февраля 2010

У меня есть веб-приложение Java-JSF на GlassFish, в котором я хочу использовать пул соединений. Поэтому я создал application bean-объект в области видимости, который служит с Connection экземплярами для других bean-компонентов:

public class DatabaseBean {

    private DataSource myDataSource;

    public DatabaseBean() {
        try {
            Context ctx = new InitialContext();
            ecwinsDataSource = (DataSource) ctx.lookup("jdbc/myDataSource");
        } catch (NamingException ex) {
            ex.printStackTrace();
        }
    }

    public Connection getConnection() throws ClassNotFoundException, SQLException, InstantiationException, IllegalAccessException {
        Connection connection = myDataSource.getConnection();
        System.out.println("Succesfully connected: " + connection);
        //Sample: Succesfully connected: com.sun.gjc.spi.jdbc40.ConnectionHolder40@7fb213a5
        return connection;
    }
}

Таким образом, пул соединений заполняется очень быстро; после нескольких переходов по представлениям, связанным с БД, приложение останавливается со следующим:

RAR5117: Не удалось получить / создать соединение из пула соединений [mysql_testPool]. Причина: используемые соединения равны максимальному размеру пула и истекшему максимальному времени ожидания. Невозможно выделить больше соединений. RAR5114: Ошибка при назначении соединения: [Ошибка при назначении соединения. Причина. Используемые соединения равны максимальному размеру пула и истекшему максимальному времени ожидания. Невозможно выделить больше соединений.] Java.sql.SQLException: Ошибка при выделении соединения. Причина. Используемые соединения равны максимальному размеру пула и истекшему максимальному времени ожидания. Невозможно выделить больше соединений.

Я закрываю соединения и другие ресурсы в каждом методе. Приложение работает нормально с автономными подключениями.

Что я делаю не так? Любые советы или рекомендации будут оценены.

Ответы [ 2 ]

20 голосов
/ 22 февраля 2010

Исключение указывает на типичный случай кода приложения, который пропускает соединения с базой данных. Вам необходимо убедиться, что вы приобрели и , чтобы закрыть их все (Connection, Statement и ResultSet) в блоке try-with-resources тот же метод блока в соответствии с обычной идиомой JDBC.

public void create(Entity entity) throws SQLException {
    try (
        Connection connection = dataSource.getConnection();
        PreparedStatement statement = connection.prepareStatement(SQL_CREATE);
    ) { 
        statement.setSomeObject(1, entity.getSomeProperty());
        // ...
        statement.executeUpdate();
    }
}

Или когда вы не на Java 7, в блоке try-finally. Закрытие их в finally гарантирует, что они также будут закрыты в случае исключений.

public void create(Entity entity) throws SQLException {
    Connection connection = null;
    PreparedStatement statement = null;

    try { 
        connection = dataSource.getConnection();
        statement = connection.prepareStatement(SQL_CREATE);
        statement.setSomeObject(1, entity.getSomeProperty());
        // ...
        statement.executeUpdate();
    } finally {
        if (statement != null) try { statement.close(); } catch (SQLException logOrIgnore) {}
        if (connection != null) try { connection.close(); } catch (SQLException logOrIgnore) {}
    }
}

Да, вам все равно нужно закрывать соединения самостоятельно, даже при использовании пула соединений. Распространенной ошибкой среди начинающих является то, что они думают, что тогда она автоматически обработает закрытие. Это не соответствует действительности . В частности, пул соединений возвращает завернутое соединение, которое выполняет что-то вроде следующего в close ():

public void close() throws SQLException {
    if (this.connection is still eligible for reuse) {
        do not close this.connection, but just return it to pool for reuse;
    } else {
        actually invoke this.connection.close();
    }
}

Не закрытие их приведет к тому, что соединение не будет возвращено обратно в пул для повторного использования, и, таким образом, оно будет снова и снова приобретать новое, пока в БД не закончатся соединения, что приведет к сбою приложения.

Смотри также:

0 голосов
/ 22 февраля 2010

Если вам нужен пул соединений JDBC, почему бы вам не полагаться на то, что уже доступно? AFAIK, пул соединений JDBC считается более или менее стандартной функцией на этих серверах Java-приложений, и IMO, вам не следует создавать это самостоятельно, если вы просто заинтересованы в создании приложения.

Вот ссылка, с которой следует начать: http://weblogs.java.net/blog/2007/09/12/totd-9-using-jdbc-connection-pooljndi-name-glassfish-rails-application

Что вам, вероятно, следует сделать, это выяснить, как позволить вашему приложению захватывать соединение из пула с помощью jndi.

...