Транзакции с Spring и JPA

1. Обзор

В этом руководстве будет обсуждаться правильный способ настройки Spring Transactions , использование аннотации @Transactional и распространенные ошибки .

Для более подробного обсуждения основной конфигурации персистентности ознакомьтесь с учебным курсом Spring с JPA.

По сути, существует два различных способа настройки транзакций - аннотации и АОП - каждый со своими преимуществами. Мы собираемся обсудить здесь более распространенную конфигурацию аннотации.

2. Настроить транзакции

Spring 3.1 вводит в @EnableTransactionManagement аннотацию , которые мы можем использовать в @Configuration классе и включить поддержку транзакций:

@Configuration @EnableTransactionManagement public class PersistenceJPAConfig{ @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(){ //... } @Bean public PlatformTransactionManager transactionManager(){ JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager.setEntityManagerFactory( entityManagerFactoryBean().getObject() ); return transactionManager; } }

Однако, если мы используем проект Spring Boot и имеем зависимости spring-data- * или spring-tx от пути к классам, то управление транзакциями будет включено по умолчанию .

3. Настройте транзакции с помощью XML.

До версии 3.1 или если Java не подходит, вот конфигурация XML с использованием аннотаций и поддержки пространства имен:

4. Аннотация @Transactional

С настроенными транзакциями мы теперь можем аннотировать bean-компонент с помощью @Transactional либо на уровне класса, либо на уровне метода:

@Service @Transactional public class FooService { //... }

Аннотация также поддерживает дальнейшую настройку :

  • Размножение Тип сделки
  • Уровень изоляции транзакции
  • Тайм - аут для операции обернут сделки
  • флаг только для чтения - намек для поставщика сохраняемости , что сделка должна быть только для чтения
  • Откат правила для сделки

Обратите внимание: по умолчанию откат выполняется только для непроверенных исключений во время выполнения. Проверенное исключение не вызывает откат транзакции. Конечно, мы можем настроить это поведение с помощью параметров аннотации rollbackFor и noRollbackFor .

5. Возможные подводные камни

5.1. Транзакции и прокси

На высоком уровне Spring создает прокси для всех классов, аннотированных @Transactional - либо для класса, либо для любого из методов. Прокси-сервер позволяет платформе внедрять транзакционную логику до и после запущенного метода - в основном для запуска и фиксации транзакции.

Важно помнить, что, если транзакционный компонент реализует интерфейс, по умолчанию прокси будет Java Dynamic Proxy. Это означает, что будут перехвачены только вызовы внешних методов, поступающие через прокси. Любые вызовы самовызова не будут запускать транзакцию, даже если метод имеет аннотацию @Transactional .

Еще одно предостережение при использовании прокси-серверов заключается в том, что только общедоступные методы должны быть аннотированы @Transactional. Методы любой другой видимости просто игнорируют аннотацию, поскольку они не передаются через прокси.

В этой статье подробно обсуждаются дальнейшие подводные камни проксирования.

5.2. Изменение уровня изоляции

Мы также можем изменить уровень изоляции транзакции:

@Transactional(isolation = Isolation.SERIALIZABLE)

Обратите внимание, что это фактически было введено в Spring 4.1; если мы запустим приведенный выше пример до Spring 4.1, это приведет к:

org.springframework.transaction.InvalidIsolationLevelException : стандартный JPA не поддерживает настраиваемые уровни изоляции - используйте специальный JpaDialect для вашей реализации JPA

5.3. Транзакции только для чтения

Доступна только для чтения флага обычно создает путаницу, особенно при работе с JPA; из Javadoc:

Это просто подсказка для самой подсистемы транзакций; это не обязательно приведет к сбою попыток доступа для записи. Диспетчер транзакций, который не может интерпретировать подсказку только для чтения, не вызовет исключение при запросе транзакции только для чтения.

Дело в том, что мы не можем быть уверены, что вставка или обновление не произойдет, если установлен флаг readOnly . Это поведение зависит от поставщика, тогда как JPA не зависит от поставщика.

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

@Transactional( propagation = Propagation.SUPPORTS,readOnly = true )

из нетранзакционного контекста - транзакция не будет создана, а флаг readOnly будет проигнорирован.

5.4. Ведение журнала транзакций

Полезный метод понимания проблем, связанных с транзакциями, - точная настройка ведения журнала в транзакционных пакетах. Соответствующий пакет в Spring - « org.springframework.transaction», который должен быть настроен с уровнем ведения журнала TRACE.

6. Заключение

Мы рассмотрели базовую конфигурацию семантики транзакций с использованием как Java, так и XML, способы использования @Transactional и лучшие практики транзакционной стратегии.

Как всегда, код, представленный в этой статье, доступен на Github.