Проблемы с аннотацией Transactional в SpringData.

 

Управление транзакциями в SpringData осуществляется декларативно.
Для декларативного управления используется аннотация @Transactional.
Эта аннотация ставится над методом или над классом. Последнее равнозначно пометке этой аннотацией всех методов.
Класс, в котором используется @Transactional, должен быть помечен аннотацией @Component или @Controller или @Service или аналогичными.
Это необходимо для того, чтобы Spring формировал объекты этого класса как бины.
Spring при создании бина, создает его как прокси, и методы, помеченные @Transactional берет в транзакционные скобки.
Транзакционные скобки означают, что перед выполнением метода, в соответствии с параметром аннотации propagation будет создана новая или продолжена имеющаяся транзакция
Более подробно см. класс org.springframework.transaction.annotation.Propagation.
Следует помнить, что Spring не изменяет класс, а использует его прокси!
Поэтому, вызов бин-прокси.method1() будет реализован с транзакционными скобками, а вызов this.method1() или объектКласса.method1() – будет по-прежнему без транзакционных скобок.
В интернете часто можно найти таинственное правило – метод, помеченный аннотацией @Transactional нельзя вызывать из тела класса (внутри метода этого же класса),
а надо вызывать его из методов другого класса, иначе аннотация не будет работать.
На самом деле никакой таинственности здесь нет. Просто, когда вызывают метод класса в теле класса, то пишут method1(), что означает this.method1() и транзакционные скобки не работают.
А когда вызывают метод из другого класса, то в другом классе получают метку на бин первого класса и пишут вызов бин-прокси.method1().
Если в классе есть ссылка на бин этого же класса (например, @Autowired ИмяКласса бин-прокси), то метод помеченный @Transactional может быть вызван внутри тела класса как бин-прокси.method1() и он будет выполнен в транзакционных скобках
Есть много других правил для работы с @Transactional:
1)Аннотация @Transactional не работает над статическими методами
2)Аннотация @Transactional не работает над default методами
3)Аннотация @Transactional не работает над private и protected методами
4)Следует отличать аннотацию org.springframework.transaction.annotation.Transactional, от javax.transaction.Transactional.
В данном случае идет разговор о org.springframework.transaction.annotation.Transactional аннотации.

Тем не менее, есть много факторов, которые могут делать ситуацию с использованием транзакций запутанной.
Например, метод помеченный @Transactional запускает выполнение другого метода в новом потоке.
Для того, чтобы разбираться в подобных ситуациях необходимо использовать диагностику транзакций.
Есть разные подходы для осуществления диагностики транзакции.

Здесь предлагается Монитор Транзакций. Он выполнен в качестве java класса TransactionMonitor.java.
Для его использования необходимо внедрить его в приложение и поставить вызов
TransactionMonitor.transactionSessionInfo(“Здесь обозначить место, где вызван монитор. Например, В начале метода method1()”);
в методы, помеченные @Transactional и в которых ситуация с транзакциями не является прозрачной.
Наверное, лучше всего ставить в начале метода, но можно ставить и в других местах метода.
Монитор транзакций соберет информацию и выведет ее в лог, с помощью метода private static void printInfo(String msg).
Состав информации следующий:
1)реализация TransactionManager. Данная версия Монитора работает только для реализации org.springframework.orm.jpa.JpaTransactionManager!
2)значение параметра hibernate.current_session_context_class
3)значение параметра jdbc.autoCommit. Если этот параметр установлен в true, то jdbc оборачивает каждый оператор insert/update/delete в транзакционные скобки и в этом случае фактически приложение не управляет транзакциями.
В частности, это означает, что @Transactional не работает или игнорируется из-за неправильного его употребления, так как реализация данной аннотации предполагает устанавку jdbc.autoCommit=false.
4)имя транзакции – как правило оно соответствует имени метода, в котором она началась и если оно null, то транзакция, вероятно, не стартовала.
5)ресурсы транзакции – прежде всего сессии – EntityManager(ы) (или Session(ы)), охватываемые транзакцией.
6)помечена ли сессия как rollBackOnly
7)другие параметры
Итак, просто включите в java проект TransactionMonitor.java и добавьте TransactionMonitor.transactionSessionInfo( label ) в методы, помеченные @Transactional;

Загрузить Монитор Транзакций можно здесь Монитор транзакций или здесь git

Добавить комментарий