Как создавать различные диспетчеры транзакций и как они связаны с соответствующими ресурсами, которые должны быть синхронизированы с транзакциями (например, DataSourceTransactionManager с DataSource из JDBC, HibernateTransactionManager с SessionFactory из Hibernate и так далее), должно теперь быть понятно. В этом разделе описано, как код приложения (прямо или косвенно, с помощью API-интерфейса сохраняемости, такого как JDBC, Hibernate или JPA) обеспечивает создание, повторное использование и очистку этих ресурсов должным образом. В разделе также рассмотрено то, каким образом синхронизацию транзакций (опционально) можно запустить через соответствующий TransactionManager.

Подход с использованием высокоуровневой синхронизации

Предпочтительным подходом является использование высокоуровневых интеграционных API-интерфейсов сохраняемости на основе шаблонов из Spring или использование собственных ORM API-интерфейсов с транзакционно-ориентированными бинами-фабриками или прокси для управления нативными фабриками ресурсов. Эти транзакционно-ориентированные решения на внутреннем уровне обрабатывают создание и повторное использование ресурсов, очистку, опциональную синхронизацию ресурсов с транзакциями и преобразованием исключений. Таким образом, пользовательскому коду доступа к данным не нужно решать эти задачи, а вместо этого его можно переориентировать исключительно на нестереотипную логику сохраняемости данных. Как правило, вы используете встроенный ORM API-интерфейс или применяете подход, основанный на шаблонах, для получения доступа по стандарту JDBC с помощью JdbcTemplate. Эти программные решения подробно описаны в последующих разделах данной справочной документации.

Подход с использованием низкоуровневой синхронизации

Такие классы, как DataSourceUtils (для JDBC), EntityManagerFactoryUtils (для JPA), SessionFactoryUtils (для Hibernate) и так далее, существуют на более низком уровне. Если вам нужно, чтобы код приложения работал непосредственно с типами ресурсов нативных API-интерфейсов сохраняемости, то используете эти классы для обеспечения получения надлежащих экземпляров, управляемых Spring Framework, синхронизации транзакций (опционально) и правильного отображения исключений, возникающих в процессе, в согласованном API-интерфейсе.

Например, в случае с JDBC, вместо традиционного для JDBC подхода с вызовом метода getConnection() для DataSource, можно использовать класс org.springframework.jdbc.datasource.DataSourceUtils из Spring, как показано ниже:

Connection conn = DataSourceUtils.getConnection(dataSource);

Если существующая транзакция уже имеет синхронизированное (привязанное) с ней соединение, возвращается этот экземпляр. В противном случае вызов метода приводит к созданию нового соединения, которое (опционально) синхронизируется с любой существующей транзакцией и становится доступным для последующего повторного использования в той же транзакции. Как упоминалось ранее, любое исключение SQLException оборачивается в исключение CannotGetJdbcConnectionException из Spring Framewor, которое является одним из исключений иерархии непроверяемых типов DataAccessException в Spring Framework. Такой подход дает больше информации, которую без проблем можно получить из SQLException, и обеспечивает переносимость между базами данных и даже между различными технологиями постоянного хранения.

Этот подход также работает без управления транзакциями из Spring (синхронизация транзакций необязательна), поэтому можно пользоваться им независимо от того, используете ли вы Spring для управления транзакциями или нет.

Естественно, после использования средств поддержки Spring для JDBC, JPA или Hibernate, обычно предпочтительнее не использовать DataSourceUtils или другие вспомогательные классы, поскольку вам будет гораздо приятнее работать через абстракцию Spring, чем напрямую с соответствующими API-интерфейсами. Например, если вы используете Spring JdbcTemplate или пакет jdbc.object для упрощения использования JDBC, корректный поиск соединения происходит "за кулисами", и вам не нужно писать специальный код.

TransactionAwareDataSourceProxy

На самом низком уровне существует класс TransactionAwareDataSourceProxy. Это прокси для целевого DataSource, который оборачивает целевой DataSource, чтобы повысить уровень совместимости транзакций, управляемых Spring, . В этом отношении он похож на транзакционный DataSource из JNDI, предоставляемый сервером Java EE.

Вам почти никогда не понадобится или не захочется использовать этот класс, за исключением случаев, когда необходимо вызвать существующий код и передать ему стандартную реализацию интерфейса DataSource из JDBC. В этом случае возможно, что этот код можно использовать, но он участвует в транзакциях, управляемых Spring. Можно написать новый собственный код, используя абстракции более высокого уровня, упомянутые ранее.