Статьи

Понимание аннотации транзакций весной

1. Введение

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

1.1 Программные транзакции

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

1.2 Декларативные операции

Декларативные транзакции отделяют код управления транзакциями от бизнес-логики. Spring поддерживает декларативные транзакции, используя рекомендации по транзакциям (используя AOP) через конфигурацию XML в контексте Spring или с аннотацией @Transactional .

В этом уроке мы особенно будем интересоваться аннотацией @Transactional и тем, как она работает.

2. Реализация

Чтобы начать использовать аннотацию @Transactional в приложении на базе Spring, нам нужно сначала включить аннотации в нашем приложении Spring, добавив необходимую конфигурацию в контекстный файл Spring —

1
<tx:annotation-driven transaction-manager="txManager"/>

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

Менеджеры транзакций могут быть:

2.1 Менеджер транзакций источника данных

1
2
3
4
<bean id="txManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref= "datasource" />
</bean>

2.2 Диспетчер транзакций Hibernate

1
2
3
4
<bean id="txManager"
        class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref= "sessionFactory" />
</bean>

2.3 JPA Менеджер транзакций

1
2
3
4
<bean id="txManager"
        class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

Теперь мы готовы использовать аннотацию @Transactional на уровне класса или метода.

1
2
3
4
@Transactional(value = "myTransactionManager", propagation = Propagation.REQUIRED, readOnly = true)
public void myMethod() {
    ...
}

3. Ссылки по теме

4. Понимание аннотации @Transactional

На высоком уровне, когда класс объявляет @Transactional для себя или своих членов, Spring создает прокси, который реализует тот же интерфейс (ы), что и класс, который вы аннотируете. Другими словами, Spring оборачивает бин в прокси, и сам бин об этом не знает. Прокси-сервер предоставляет Spring способ внедрить поведение до, после или вокруг вызовов методов в объект, который проксируется.

Внутренне, это то же самое, что использовать совет по транзакциям (используя AOP), когда прокси создается первым и вызывается до / после метода целевого компонента.

Сгенерированный прокси-объект поставляется с TransactionInterceptor , который создается Spring. Поэтому, когда метод @Transactional вызывается из клиентского кода, TransactionInterceptor сначала вызывается из прокси-объекта, который начинает транзакцию и в конечном итоге вызывает метод для целевого компонента. Когда вызов завершается, TransactionInterceptor фиксирует / откатывает транзакцию соответственно.

Обратите внимание, что через прокси проходят только вызовы «извне» целевого компонента.

5. Понимание атрибутов распространения и чтения только для комментариев

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

Если вы явно не установите атрибут readOnly в true , у вас будут транзакции чтения / записи.

Всегда лучше явно указывать атрибут readOnly , поскольку из-за этого мы заметили значительные улучшения производительности в Hibernate.

5.2 Распространение транзакции

По умолчанию ТРЕБУЕТСЯ распространение транзакции, что означает, что одна и та же транзакция будет распространяться от транзакционного вызывающего абонента до транзакционного вызываемого. Это создаст новую транзакцию или повторно использует ту, которая доступна. Например, если транзакция только для чтения вызывает метод транзакции чтения-записи, вся транзакция будет доступна только для чтения.

В зависимости от атрибута распространения транзакции (например, для REQUIRES_NEW ), иногда существующая транзакция в какой-то момент приостанавливается / приостанавливается, новая всегда запускается и в конечном итоге фиксируется, и после этого первая транзакция возобновляется.

5.3 Уровень изоляции

Уровень изоляции определяет договор между транзакциями.

  • Read Uncommitted — разрешает грязное чтение, когда транзакция еще не зафиксирована потоком, а другой поток читает грязные данные.
  • Read Committed — не допускает грязного чтения. Позволяет только потоку читать значения, которые уже были зафиксированы другими запущенными транзакциями в других потоках.
  • Повторяемое чтение — если одни и те же данные читаются дважды в одной и той же транзакции, они всегда будут одинаковыми. Этот уровень гарантирует, что любые прочитанные данные не могут измениться.
  • Сериализуемый — Транзакции происходят с блокировкой на всех уровнях (чтение, диапазон и блокировка записи), из-за чего они выполняются в фиксированной последовательности. Он не допускает одновременных транзакций и приводит к снижению производительности.

С уровнем изоляции Repeatable Read состояние базы данных поддерживается с начала транзакции. Если вы извлекаете значение в сеансе 1 , то обновляете это значение в сеансе 2 , и его повторное получение в сеансе 1 возвращает те же результаты.

6. Исходный код скачать

Ссылка: Понимание аннотации транзакций весной от нашего партнера JCG Абхиманью Прасада в блоге jCombat .