Рубрики
Без рубрики

Как работает агрессивный выпуск соединения в режиме гибернации

Автор оригинала: Vlad Mihalcea.

Hibernate должен работать как в Java EE, так и в автономных средах, а конфигурация подключения к базе данных может быть выполнена как декларативно, так и программно.

Для размещения соединений JDBC Драйвера , а также конфигураций RESOURCE_LOCAL и JTA Источника данных , Hibernate определяет собственную абстракцию фабрики соединений, представленную интерфейсом org.hibernate.engine.jdbc.connections.spi.ConnectionProvider .

public interface ConnectionProvider 
    extends Service, Wrapped {

    public Connection getConnection() 
        throws SQLException;

    public void closeConnection(Connection connection) 
        throws SQLException;
    
    public boolean supportsAggressiveRelease();
}

Поскольку поставщик подключения может влиять на время отклика транзакции, Hibernate предлагает несколько реализаций интерфейса ConnectionProvider :

  • DriverManagerConnectionProvider – который использует элементарную реализацию пула соединений, поэтому он предназначен только для сценариев тестирования
  • C3P0ConnectionProvider – использует c3p0 для объединения соединений, и это гораздо лучшая альтернатива, чем предыдущий вариант
  • DatasourceConnectionProvider – наиболее гибким выбором является использование внешнего настроенного источника данных и предоставление ему режима гибернации через не jta-источник данных или элемент |/jta-источник данных или путем настройки свойства hibernate.connection.datasource конфигурация.

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

Hibernate откладывает получение соединения с базой данных до тех пор, пока текущая транзакция не выполнит свою первую инструкцию SQL (либо инициированную операцией чтения, либо записью). Эта оптимизация позволяет Hibernate сократить интервал физических транзакций, тем самым увеличивая вероятность получения соединения из пула.

Стратегия освобождения соединения контролируется с помощью hibernate.connection.release_mode свойство, которое может принимать следующие значения:

after_transaction После получения соединение с базой данных освобождается только после фиксации или отката текущей транзакции.
after_statement Соединение освобождается после выполнения каждой инструкции и повторно запрашивается перед запуском следующей инструкции. Хотя это не требуется ни спецификациями JDBC, ни спецификациями JTA, эта стратегия предназначена для предотвращения ошибочного обнаружения серверами приложений утечки соединения между последовательными вызовами EJB (корпоративные компоненты Java).
авто Это значение по умолчанию, и для транзакций RESOURCE_LOCAL он использует режим after_transaction, в то время как для транзакций JTA он возвращается к after_statement.

Для получения более подробной информации о том, почему был введен режим освобождения агрессивного подключения, ознакомьтесь с проблемой HHH-1287 Hibernate Jira.

Для транзакций JTA режим по умолчанию может быть слишком строгим, поскольку не все серверы приложений Java EE демонстрируют одинаковое поведение при управлении транзакционными ресурсами. Таким образом, важно проверить, могут ли соединения с базой данных быть закрыты за пределами компонента EJB, который инициировал событие получения соединения. Корпоративные системы на базе Spring не используют корпоративные JavaBeans, и даже при использовании автономного диспетчера транзакций JTA режим выпуска after_transaction соединения может быть просто прекрасным.

Как-то интуитивно понятно, что режим after_statement приводит к некоторому снижению производительности, связанному с частыми циклами получения/освобождения соединения. По этой причине в следующем тесте измеряются затраты на получение соединения при использовании Bitronix в контексте приложения Spring. Каждая транзакция выполняет одну и ту же инструкцию (получение текущей метки времени) заданное количество раз (представлено на оси x).

Ось y фиксирует записанное время отклика транзакции для обоих режимов after_statement и after_transaction освобождения соединения.

Чем больше инструкций выполнит транзакция, тем больше штраф за повторный запрос соответствующего подключения к базе данных из базового пула соединений. Чтобы лучше визуализировать накладные расходы на получение соединения, тест выполняется до 10000 выписки, даже если это число, вероятно, слишком велико для типичной транзакции OLTP.

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

Режим after_transaction освобождения соединения более эффективен, чем стратегия JTA after_statement по умолчанию, и поэтому его следует использовать, если логика управления ресурсами транзакций JTA не мешает этой стратегии освобождения соединения.