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

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

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 ответа

Решение

Исключение указывает на типичный случай кода приложения, который пропускает соединения с базой данных. Вы должны убедиться, что вы приобретаете и закрываете их все (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();
    }
}

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

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

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

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

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

Другие вопросы по тегам