使用Spring AOP进行事务回滚

3

我很新于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故意引发异常(该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
3个回答

2
尝试将您的AOP表达式更改为包括服务接口(如果它们没有被覆盖)。我曾经遇到过这样的问题,我的服务接口与服务实现不在同一个包中,如果它们没有被AOP表达式覆盖,则事务不会启动/提交/回滚。
另外,如果这是一个Web应用程序,请考虑放弃AOP,转而使用Spring的OpenSessionInViewFilter,它会在请求到达时打开一个会话,并在返回/抛出后提交/回滚。
最后,我使用IntelliJ IDE,它具有很好的Spring支持 - 您可以单击XML文件中的AOP声明,并查看模式匹配的所有方法的弹出列表 - 这真的有助于调试AOP。

我认为你在这方面走上了正确的轨道。尝试调试你的代码,看看 Advice 是否在它应该被调用的时候实际上被调用了,然后再处理其中的实际业务逻辑。此外,我一直发现将我的 Aspect 切入点定义为某个注解,并将该注解放置在所需方法的顶部,会更清晰、更简洁。 - Shivan Dragon
感谢SingleShot指针。我正在调试,但仍然感到困惑。请参见上面的编辑。 - Vijay Thakre
我投了票,觉得很有用,谢谢新的见解。:) 但是关于更改(放弃AOP或使用intelliJ),由于应用程序已经使用多年,我只能修改那么多。这也取决于我将在这个项目上工作多长时间。是的,我会将其更改为注释(@Transactional),而不是现有的XML配置。 - Vijay Thakre

1

我认为你需要在你的上下文中添加<aop:aspectj-autoproxy/>。这是一个将切面应用于你的bean的指令。aop:configtx:advice只是设置了一个切面,我认为它没有被应用。

你也可以通过打开Spring的信息日志来验证你的类是否被切入和事务是否启动/回滚。

另外,如果你使用的是Java 1.5或更高版本,最好/更容易使用基于注释的配置(@Transactional)而不是基于XML的配置。


抱歉 aop:aspectj-autoproxy/ 没有帮助。 :-( - Vijay Thakre
我已经摆脱了基于XML的配置,现在使用@Trasactional。但问题仍然存在。日志显示正在回滚(某些内容),但是MySQL数据库中的数据已经消失了。 - Vijay Thakre
存储引擎是什么 - 如果它是MyISAM,我认为它不支持事务。你需要改用InnoDB。 - gkamal
它是InnoDB。我在配置文件中设置了hibernate.dialect=org.hibernate.dialect.MySQLDialect。我已经尝试将其更改为hibernate.dialect=org.hibernate.dialect.MySQLInnoDBDialect还尝试了<bean id="mySqlDataSource" p:aurocommit="false"但都没有奏效。问题通过将Transaction更改为HibernateTransactionManager得到解决。 - Vijay Thakre
这是与数据库中表相关联的存储引擎。您可以在以下链接中找到有关如何检查和更改的信息 - http://www.electrictoolbox.com/mysql-table-storage-engine/ - gkamal
刚刚离开了办公室。我明天会进行相应的检查。但是我想声明一下,当我说它是InnoDB时,我是通过MySQL Workbench - Table来检查的。但是我明天在工作中会再次确认。 - Vijay Thakre

0

明白了。或者我应该说问题解决了,但并不真正理解为什么。

将我的 Transaction bean 类从 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>

现在太麻木了,回家了。有人能解释一下这是为什么吗?


如果您正在通过Hibernate进行删除操作,我认为问题并没有解决。Hibernate不会将删除语句发送到数据库,因此更改为HibernateTransactionManager(这是正确的做法)可能掩盖了原始问题。您可以在抛出异常之前调用session.flush()来检查这一点。我仍然认为问题是由于MySQL存储引擎引起的。 - gkamal
请问您能否提供为什么使用HibernateTransactionManager更好的链接?谢谢。 - Vijay Thakre
http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html 上有一些信息。基本上,您希望为整个事务创建一个单独的Hibernate Session,而不是每个dao调用一个。 HibernateTransactionManager将确保这一点。 - gkamal
1
还有一件事 - Hibernate SessionFactory 是如何获取数据源的?是通过Spring注入还是直接在hibernate.cfg.xml中配置?这就是为什么它不能与DataSourceTransactionManager一起使用,但一旦更改为HibernateTransactionManager就可以工作的原因之一。 - gkamal
不确定我是否理解了。但是注入是通过Spring进行的。我的hibernate.cfg.xml仅具有实体映射。 applicationContext.xml具有<bean id="mySqlDataSource" /> <bean id="mySqlSessionFactory" ...> <property name="configLocation" value="WEB-INF/hibernate.cfg.xml"/>还有 <bean id="pejlAnalysisDao" class="PejlAnalysisDaoImpl"> - Vijay Thakre
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接