1. Обзор
В этом руководстве будет обсуждаться правильный способ настройки Spring Транзакций , использование аннотации @Transactional и распространенных ошибок.
Для более глубокого обсуждения основной конфигурации персистентности ознакомьтесь с руководством по Spring с JPA .
Существует два различных способа настройки транзакций — аннотации и AOP, каждый из которых имеет свои преимущества — здесь мы обсудим более распространенную конфигурацию аннотаций .
2. Настройте транзакции без XML
Spring 3.1 представляет аннотацию @EnableTransactionManagement, которая будет использоваться в классах @Configuration, и включает поддержку транзакций:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
@Configuration @EnableTransactionManagement public class PersistenceJPAConfig{ @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(){ ... } @Bean public PlatformTransactionManager transactionManager(){ JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager.setEntityManagerFactory( entityManagerFactoryBean().getObject() ); return transactionManager; } } |
3. Настройте транзакции с помощью XML
До 3.1 или, если Java не вариант, вот конфигурация XML , использующая аннотации и поддержку пространства имен:
1
2
3
4
|
< bean id = "txManager" class = "org.springframework.orm.jpa.JpaTransactionManager" > < property name = "entityManagerFactory" ref = "myEmf" /> </ bean > < tx:annotation-driven transaction-manager = "txManager" /> |
4. Аннотация @Transactional
С настроенными транзакциями, bean-компонент теперь может быть аннотирован @Transactional на уровне класса или метода:
1
2
3
4
5
|
@Service @Transactional public class FooService { ... } |
Аннотация также поддерживает дальнейшую настройку :
- Тип распространения сделки
- Уровень изоляции транзакции
- Тайм-аут для операции, завернутой транзакцией
- флаг readOnly — подсказка для поставщика постоянства, что транзакция должна быть только для чтения
- подробная конфигурация отката
5. Потенциальные ловушки
5.1. Транзакции и Прокси
На высоком уровне Spring создает прокси для всех классов, помеченных @Transactional — либо для класса, либо для любого из методов. Прокси-сервер позволяет платформе внедрять транзакционную логику до и после вызова метода — главным образом для запуска и фиксации транзакции .
Важно помнить, что если транзакционный компонент реализует интерфейс, по умолчанию прокси будет динамическим прокси Java . Это означает, что будут перехватываться только внешние вызовы методов, которые поступают через прокси-сервер — любые вызовы самозапуска не будут запускать какие-либо транзакции — даже если метод аннотирован @Transactional .
Еще одна оговорка использования прокси-серверов заключается в том, что аннотацией @Transactional следует аннотировать только общедоступные методы — методы любой другой видимости будут просто молча игнорировать аннотацию, поскольку они не проксируются.
В этой статье подробно обсуждаются дальнейшие прокси-серверы .
5.2. Изменение уровня изоляции
Одна из основных ловушек при настройке Spring для работы с JPA заключается в том, что изменение изоляции семантики транзакции не будет работать — JPA не поддерживает настраиваемые уровни изоляции . Это ограничение JPA, а не Spring ; тем не менее изменение свойства изоляции @Transactional приведет к:
org.springframework.transaction.InvalidIsolationLevelException: стандартный JPA не поддерживает настраиваемые уровни изоляции — используйте специальный JpaDialect для реализации JPA
5.3. Только для чтения транзакции
Флаг readOnly обычно создает путаницу, особенно при работе с JPA; из Javadoc:
Это просто подсказка для действующей подсистемы транзакций; это не обязательно приведет к сбою попыток доступа для записи. Менеджер транзакций, который не может интерпретировать подсказку только для чтения, не вызовет исключение при запросе транзакции только для чтения.
Дело в том, что нельзя гарантировать, что вставка или обновление не произойдут, если установлен флаг readOnly — его поведение зависит от поставщика, тогда как JPA не зависит от поставщика.
Также важно понимать, что флаг readOnly имеет значение только внутри транзакции ; если операция происходит вне контекста транзакции, флаг просто игнорируется. Простой пример этого — вызов метода с аннотацией:
1
|
@Transactional ( propagation = Propagation.SUPPORTS,readOnly = true ) |
из нетранзакционного контекста — транзакция не будет создана, а флаг readOnly будет игнорироваться.
5.4. Регистрация транзакций
Проблемы, связанные с транзакциями, также могут быть лучше поняты путем тонкой настройки регистрации в транзакционных пакетах; соответствующий пакет в Spring — « org.springframework.transaction», который должен быть настроен с уровнем ведения журнала TRACE.
6. Заключение
Мы рассмотрели базовую конфигурацию транзакционной семантики с использованием как Java, так и XML, как использовать @Transactional и лучшие практики транзакционной стратегии. Также обсуждалась поддержка Spring для транзакционного тестирования, а также некоторые распространенные ошибки JPA .
Реализацию этого простого проекта можно найти в проекте github — это проект на основе Eclipse, поэтому его легко импортировать и запускать как есть.