Откат транзакции с помощью Spring — AOP

#hibernate #spring #aop

#спящий режим #spring #aop

Вопрос:

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

Мой конфигурационный файл Spring

 <beans...>
     <!-- This TX is I am interested in -->      
     <bean id="transactionManager"
           class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
               <property name="dataSource" ref="mySqlDataSource"/>  
     </bean>

      <bean id="registriesTransactionManager"
           class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
         <property name="dataSource" ref="registriesDataSource"/>
     </bean> <!-- There are 2 datasorce for AS400 and a transaction for one of them-->

     <aop:config>
         <aop:advisor pointcut="execution(* se.unox.pejl.service.PejlAnalysisService.* (..))" advice-ref="txMySqlAdvice"/>                    
         <! ---   many more --> 
     </aop:config>

     <tx:advice id="txMySqlAdvice" transaction-manager="transactionManager">
       <tx:attributes>
         <tx:method name="get*" read-only="true" />
         <tx:method name="*" />             
         <tx:method name="cleanPejlValues" propagation="REQUIRED" rollback-for="Throwable"/>    
       </tx:attributes>
    </tx:advice> 

</beans>
  

Моя реализация сервиса

 public class PejlAnalysisServiceImpl implements PejlAnalysisService, InitializingBean     {
    @Override
    public void cleanPejlValues() {
         List<String> idsToDelete= pejlDataDao.getPejlIds(Calendar.getInstance().getTime(), pejlType);

         logger.debug("TRYING TO DELETE these IDS: "   idsToDelete);

         numDeletedValues  = cisternDao.deleteCistern(idsToDelete);

         logger.debug("DELETED "   numDeletedValues);
         numDeletedValues  = pejlDataDao.deletePejlValues(idsToDelete);
     }
 }
  

Мой DAO, из которого я выбрасываю исключение

 public class PejlDataDaoMySqlImpl extends GenericDaoImpl<PejlDataInValue,String> implements PejlDataDao {

  @Override
  public int deletePejlValues(List<String> pejlIds)      {          
    throw new RuntimeException("THROW INTENTIONALLY");          
  }
}
  

Я хочу, чтобы удаленные строки CisternDao (таблица tbl_cistern) были откатаны после того, как я (намеренно) создаю исключение из другого Dao, которое предполагает удаление данных из родительской таблицы.

Однако мой откат не работает. Данные таблицы tbl_cistern по-прежнему отсутствуют.

Что я делаю не так? (Я использую Spring 3.1, Spring AOP -3.1, Hibernate 3.6, Tomcat6)

===============================================================================

Редактировать.

Вот мой AOP StackTrace. Он говорит откат, но мои строки из первой таблицы все еще отсутствуют. Это существующее приложение. Интересно, мешает ли DomainServiceImpl TX.

 2011-10-12 11:46:27,726 DEBUG - Creating new transaction with name [se.unox.pejl.service.impl.PejlAnalysisServiceImpl.cleanPejlValues]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-Throwable
2011-10-12 11:46:27,726 DEBUG - Creating new transaction with name [se.unox.pejl.service.impl.PejlAnalysisServiceImpl.cleanPejlValues]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-Throwable
2011-10-12 11:46:27,726 DEBUG - Acquired Connection [jdbc:mysql://localhost:3306/pejldatastorenorway?autoReconnect=true, UserName=dbpejl@localhost, MySQL-AB JDBC Driver] for JDBC transaction
2011-10-12 11:46:27,726 DEBUG - Acquired Connection [jdbc:mysql://localhost:3306/pejldatastorenorway?autoReconnect=true, UserName=dbpejl@localhost, MySQL-AB JDBC Driver] for JDBC transaction
2011-10-12 11:46:27,727 DEBUG - Switching JDBC Connection [jdbc:mysql://localhost:3306/pejldatastorenorway?autoReconnect=true, UserName=dbpejl@localhost, MySQL-AB JDBC Driver] to manual commit
2011-10-12 11:46:27,727 DEBUG - Switching JDBC Connection [jdbc:mysql://localhost:3306/pejldatastorenorway?autoReconnect=true, UserName=dbpejl@localhost, MySQL-AB JDBC Driver] to manual commit
2011-10-12 11:46:27,727 DEBUG - Bound value [org.springframework.jdbc.datasource.ConnectionHolder@6113e0] for key [org.apache.commons.dbcp.BasicDataSource@ee003d] to thread [http-8080-1]
2011-10-12 11:46:27,727 DEBUG - Bound value [org.springframework.jdbc.datasource.ConnectionHolder@6113e0] for key [org.apache.commons.dbcp.BasicDataSource@ee003d] to thread [http-8080-1]
2011-10-12 11:46:27,727 DEBUG - Initializing transaction synchronization
2011-10-12 11:46:27,727 DEBUG - Initializing transaction synchronization
2011-10-12 11:46:27,728 DEBUG - Getting transaction for [se.unox.pejl.service.impl.PejlAnalysisServiceImpl.cleanPejlValues]
2011-10-12 11:46:27,728 DEBUG - Getting transaction for [se.unox.pejl.service.impl.PejlAnalysisServiceImpl.cleanPejlValues]
2011-10-12 11:46:27,729 DEBUG - Retrieved value [org.springframework.jdbc.datasource.ConnectionHolder@6113e0] for key [org.apache.commons.dbcp.BasicDataSource@ee003d] bound to thread [http-8080-1]
2011-10-12 11:46:27,729 DEBUG - Retrieved value [org.springframework.jdbc.datasource.ConnectionHolder@6113e0] for key [org.apache.commons.dbcp.BasicDataSource@ee003d] bound to thread [http-8080-1]
2011-10-12 11:46:27,729 DEBUG - Participating in existing transaction
2011-10-12 11:46:27,729 DEBUG - Participating in existing transaction
2011-10-12 11:46:27,729 DEBUG - Getting transaction for [se.unox.pejl.service.impl.DomainServiceImpl.getDomainData]
2011-10-12 11:46:27,729 DEBUG - Getting transaction for [se.unox.pejl.service.impl.DomainServiceImpl.getDomainData]
2011-10-12 11:46:27,730 DEBUG - Bound value [org.springframework.orm.hibernate3.SessionHolder@160088f] for key [org.hibernate.impl.SessionFactoryImpl@1a0280d] to thread [http-8080-1]
2011-10-12 11:46:27,730 DEBUG - Bound value [org.springframework.orm.hibernate3.SessionHolder@160088f] for key [org.hibernate.impl.SessionFactoryImpl@1a0280d] to thread [http-8080-1]
2011-10-12 11:46:27,730 DEBUG - Retrieved value [org.springframework.orm.hibernate3.SessionHolder@160088f] for key [org.hibernate.impl.SessionFactoryImpl@1a0280d] bound to thread [http-8080-1]
2011-10-12 11:46:27,730 DEBUG - Retrieved value [org.springframework.orm.hibernate3.SessionHolder@160088f] for key [org.hibernate.impl.SessionFactoryImpl@1a0280d] bound to thread [http-8080-1]
2011-10-12 11:46:27,734 DEBUG - Completing transaction for [se.unox.pejl.service.impl.DomainServiceImpl.getDomainData]
2011-10-12 11:46:27,734 DEBUG - Completing transaction for [se.unox.pejl.service.impl.DomainServiceImpl.getDomainData]
2011-10-12 11:46:27,734 DEBUG - Retrieved value [org.springframework.jdbc.datasource.ConnectionHolder@6113e0] for key [org.apache.commons.dbcp.BasicDataSource@ee003d] bound to thread [http-8080-1]
2011-10-12 11:46:27,734 DEBUG - Retrieved value [org.springframework.jdbc.datasource.ConnectionHolder@6113e0] for key [org.apache.commons.dbcp.BasicDataSource@ee003d] bound to thread [http-8080-1]
2011-10-12 11:46:27,734 DEBUG - Participating in existing transaction
2011-10-12 11:46:27,734 DEBUG - Participating in existing transaction
2011-10-12 11:46:27,734 DEBUG - Getting transaction for [se.unox.pejl.service.impl.DomainServiceImpl.getDomainData]
2011-10-12 11:46:27,734 DEBUG - Getting transaction for [se.unox.pejl.service.impl.DomainServiceImpl.getDomainData]
2011-10-12 11:46:27,735 DEBUG - Retrieved value [org.springframework.orm.hibernate3.SessionHolder@160088f] for key [org.hibernate.impl.SessionFactoryImpl@1a0280d] bound to thread [http-8080-1]
2011-10-12 11:46:27,735 DEBUG - Retrieved value [org.springframework.orm.hibernate3.SessionHolder@160088f] for key [org.hibernate.impl.SessionFactoryImpl@1a0280d] bound to thread [http-8080-1]
2011-10-12 11:46:27,735 DEBUG - Completing transaction for [se.unox.pejl.service.impl.DomainServiceImpl.getDomainData]
2011-10-12 11:46:27,735 DEBUG - Completing transaction for [se.unox.pejl.service.impl.DomainServiceImpl.getDomainData]
2011-10-12 11:46:27,735 DEBUG - Retrieved value [org.springframework.jdbc.datasource.ConnectionHolder@6113e0] for key [org.apache.commons.dbcp.BasicDataSource@ee003d] bound to thread [http-8080-1]
2011-10-12 11:46:27,735 DEBUG - Retrieved value [org.springframework.jdbc.datasource.ConnectionHolder@6113e0] for key [org.apache.commons.dbcp.BasicDataSource@ee003d] bound to thread [http-8080-1]
2011-10-12 11:46:27,735 DEBUG - Participating in existing transaction
2011-10-12 11:46:27,735 DEBUG - Participating in existing transaction
2011-10-12 11:46:27,735 DEBUG - Getting transaction for [se.unox.pejl.service.impl.DomainServiceImpl.getDomainData]
2011-10-12 11:46:27,735 DEBUG - Getting transaction for [se.unox.pejl.service.impl.DomainServiceImpl.getDomainData]
2011-10-12 11:46:27,735 DEBUG - Retrieved value [org.springframework.orm.hibernate3.SessionHolder@160088f] for key [org.hibernate.impl.SessionFactoryImpl@1a0280d] bound to thread [http-8080-1]
2011-10-12 11:46:27,735 DEBUG - Retrieved value [org.springframework.orm.hibernate3.SessionHolder@160088f] for key [org.hibernate.impl.SessionFactoryImpl@1a0280d] bound to thread [http-8080-1]
2011-10-12 11:46:27,737 DEBUG - Completing transaction for [se.unox.pejl.service.impl.DomainServiceImpl.getDomainData]
2011-10-12 11:46:27,737 DEBUG - Completing transaction for [se.unox.pejl.service.impl.DomainServiceImpl.getDomainData]
2011-10-12 11:46:27,737 DEBUG - Retrieved value [org.springframework.orm.hibernate3.SessionHolder@160088f] for key [org.hibernate.impl.SessionFactoryImpl@1a0280d] bound to thread [http-8080-1]
2011-10-12 11:46:27,737 DEBUG - Retrieved value [org.springframework.orm.hibernate3.SessionHolder@160088f] for key [org.hibernate.impl.SessionFactoryImpl@1a0280d] bound to thread [http-8080-1]
2011-10-12 11:46:27,789 DEBUG - Retrieved value [org.springframework.orm.hibernate3.SessionHolder@160088f] for key [org.hibernate.impl.SessionFactoryImpl@1a0280d] bound to thread [http-8080-1]
2011-10-12 11:46:27,789 DEBUG - Retrieved value [org.springframework.orm.hibernate3.SessionHolder@160088f] for key [org.hibernate.impl.SessionFactoryImpl@1a0280d] bound to thread [http-8080-1]
2011-10-12 11:46:28,396 DEBUG - Completing transaction for [se.unox.pejl.service.impl.PejlAnalysisServiceImpl.cleanPejlValues] after exception: java.lang.RuntimeException: THROWN INTENTIONALLY
2011-10-12 11:46:28,396 DEBUG - Completing transaction for [se.unox.pejl.service.impl.PejlAnalysisServiceImpl.cleanPejlValues] after exception: java.lang.RuntimeException: THROWN INTENTIONALLY
2011-10-12 11:46:28,396 DEBUG - Applying rules to determine whether transaction should rollback on java.lang.RuntimeException: THROWN INTENTIONALLY
2011-10-12 11:46:28,396 DEBUG - Applying rules to determine whether transaction should rollback on java.lang.RuntimeException: THROWN INTENTIONALLY
2011-10-12 11:46:28,396 DEBUG - Winning rollback rule is: RollbackRuleAttribute with pattern [Throwable]
2011-10-12 11:46:28,396 DEBUG - Winning rollback rule is: RollbackRuleAttribute with pattern [Throwable]
2011-10-12 11:46:28,396 DEBUG - Triggering beforeCompletion synchronization
2011-10-12 11:46:28,396 DEBUG - Triggering beforeCompletion synchronization
2011-10-12 11:46:28,397 DEBUG - Removed value [org.springframework.orm.hibernate3.SessionHolder@160088f] for key [org.hibernate.impl.SessionFactoryImpl@1a0280d] from thread [http-8080-1]
2011-10-12 11:46:28,397 DEBUG - Removed value [org.springframework.orm.hibernate3.SessionHolder@160088f] for key [org.hibernate.impl.SessionFactoryImpl@1a0280d] from thread [http-8080-1]
2011-10-12 11:46:28,397 DEBUG - Initiating transaction rollback
2011-10-12 11:46:28,397 DEBUG - Initiating transaction rollback
2011-10-12 11:46:28,397 DEBUG - Rolling back JDBC transaction on Connection [jdbc:mysql://localhost:3306/pejldatastorenorway?autoReconnect=true, UserName=dbpejl@localhost, MySQL-AB JDBC Driver]
2011-10-12 11:46:28,397 DEBUG - Rolling back JDBC transaction on Connection [jdbc:mysql://localhost:3306/pejldatastorenorway?autoReconnect=true, UserName=dbpejl@localhost, MySQL-AB JDBC Driver]
2011-10-12 11:46:28,398 DEBUG - Triggering afterCompletion synchronization
2011-10-12 11:46:28,398 DEBUG - Triggering afterCompletion synchronization
2011-10-12 11:46:28,398 DEBUG - Clearing transaction synchronization
2011-10-12 11:46:28,398 DEBUG - Clearing transaction synchronization
2011-10-12 11:46:28,398 DEBUG - Removed value [org.springframework.jdbc.datasource.ConnectionHolder@6113e0] for key [org.apache.commons.dbcp.BasicDataSource@ee003d] from thread [http-8080-1]
2011-10-12 11:46:28,398 DEBUG - Removed value [org.springframework.jdbc.datasource.ConnectionHolder@6113e0] for key [org.apache.commons.dbcp.BasicDataSource@ee003d] from thread [http-8080-1]
2011-10-12 11:46:28,399 DEBUG - Releasing JDBC Connection [jdbc:mysql://localhost:3306/pejldatastorenorway?autoReconnect=true, UserName=dbpejl@localhost, MySQL-AB JDBC Driver] after transaction
2011-10-12 11:46:28,399 DEBUG - Releasing JDBC Connection [jdbc:mysql://localhost:3306/pejldatastorenorway?autoReconnect=true, UserName=dbpejl@localhost, MySQL-AB JDBC Driver] after transaction
2011-10-12 11:46:28,399 DEBUG - Returning JDBC Connection to DataSource
2011-10-12 11:46:28,399 DEBUG - Returning JDBC Connection to DataSource
2011-10-12 11:30:36,577 DEBUG - Releasing JDBC Connection [jdbc:mysql://localhost:3306/pejldatastorenorway?autoReconnect=true, UserName=dbpejl@localhost, MySQL-AB JDBC Driver] after transaction
  

Ответ №1:

Попробуйте изменить выражения AOP, чтобы также включить интерфейсы служб (если они не охвачены). У меня были проблемы, когда мои интерфейсы служб находились в пакете, отличном от реализаций служб, и если они не охватываются выражением AOP, транзакции не запускаются / не фиксируются / не выполняются.

Кроме того, если это веб-приложение, рассмотрите возможность отказа от AOP в пользу Spring OpenSessionInViewFilter, который открывает сеанс при поступлении запроса и фиксирует / откатывает его после возврата / возврата.

Наконец, я использую IntelliJ IDE, которая имеет отличную поддержку Spring — вы можете щелкнуть объявление AOP в XML-файле и увидеть всплывающий список всех методов, соответствующих шаблону, — действительно помогает при отладке AOP.

Комментарии:

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

2. Спасибо за одиночный снимок указателя. Я отлаживаю, но все еще в замешательстве. См. Редактирование выше.

3. Я проголосовал за полезное, спасибо за новые идеи. 🙂 Но об изменениях (удаление AOP или использование IntelliJ) я могу изменять только столько, сколько приложение уже используется годами. Зависит от того, как долго я буду работать над этим проектом. И да. Я изменю его на аннотацию (@Transactional) вместо существующей конфигурации XML.

Ответ №2:

Я думаю, вам нужно добавить <aop:aspectj-autoproxy/> в свой контекст. Это инструкция по применению аспектов к вашим компонентам. aop:config и tx:advice просто настройте аспект, который, я думаю, не применяется.

Вы также можете проверить, являются ли ваши классы аспектированными, и транзакции запускаются / откатываются, включив ведение журнала информации для spring.

В качестве дополнительного примечания, если вы используете java 1.5 или более позднюю версию, намного лучше / проще использовать аннотации (@Transactional) вместо конфигурации на основе XML.

Комментарии:

1. извините <aop:aspectj-autoproxy/> не помогло. 🙁

2. Я избавился от конфигурации на основе XML и теперь использую @Trasactional. проблема по-прежнему сохраняется. В журналах говорится, что он откатывается (что-то), но данные в базе данных MySQL исчезли.

3. Что такое механизм хранения — если это MyISAM, я думаю, он не поддерживает транзакции. Вам нужно перейти на InnoDB.

4. Его InnoDB. У меня был hibernate.dialect=org.hibernate.dialect. MySQLDialect в моей конфигурации. Уже пробовал изменить его на hibernate.dialect=org.hibernate.dialect. MySQLInnoDBDialect также пытался Проблема решается путем изменения транзакции на HibernateTransactionManager.

5. не диалект — механизм хранения, связанный с таблицей в базе данных. Вы можете найти информацию о том, как проверить и изменить — electrictoolbox.com/mysql-table-storage-engine

Ответ №3:

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

Изменен мой класс компонента транзакции из org.springframework.jdbc.datasource.DataSourceTransactionManager

Для

org.springframework.orm.hibernate3.HibernateTransactionManager

И его работа.

  <bean id="transactionManager"  class="org.springframework.orm.hibernate3.HibernateTransactionManager">
      <!--  class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> -->
     <property name="sessionFactory" ref="mySqlSessionFactory"></property>

   <!--  <property name="dataSource" ref="mySqlDataSource"/>  -->       
</bean>
  

Сейчас слишком оцепенел, иду домой. Кто-нибудь может пролить свет на то, почему это так?

Комментарии:

1. Если вы выполняете удаление через спящий режим, я думаю, что проблема не решена. Спящий режим не отправляет инструкции delete в базу данных, поэтому переход на HibernateTransactionManager (что правильно) может маскировать исходную проблему. Вы можете проверить это, вызвав session . flush() перед выдачей исключения. Я все еще думаю, что проблема связана с механизмом хранения mysql.

2. Не могли бы вы указать, почему использование HibernateTransactionManager лучше? Спасибо.

3. static.springsource.org/spring/docs/2.0.x/reference /… имеет некоторую информацию. По сути, вы хотите, чтобы для всей транзакции был создан один сеанс гибернации вместо одного для каждого вызова dao. HibernateTransactionManager обеспечит это.

4. ВЫБЕРИТЕ ИМЯ_ТАБЛИЦЫ, ДВИЖОК ИЗ information_schema. ТАБЛИЦЫ, В КОТОРЫХ TABLE_SCHEMA = ‘pejldatastorenorway’ возвращал «InnoDB».

5. Еще одна вещь — как hibernate sessionfactory получает источник данных, вводится ли он через spring или напрямую настраивается в hibernate.cfg.xml . Это одна из причин, по которой он не будет работать с DataSourceTransactionManager, но будет работать после изменения на HibernateTransactionManager.