Spring Transaction没有回滚

时间:2016-10-21 09:55:46

标签: java spring rollback spring-transactions

我有这样的事情:

@Service
@Transactional
public class ServiceA {

    @Autowired
    SomeDAO1 dao1; 

    @Autowired
    ServiceB serviceB;

    public void methodServiceA() {

        serviceB.someMethodThatRunsInsertIntoDB(); 
        dao1.anotherMethodThatRunsInsertIntoDB(); 

    }

}

@Service
@Transactional
public class ServiceB {

     @Autowired
     Dao2 dao2;

     public void someMethodThatRunsInsertIntoDB() {
          dao2.insertXXX();
     }

}

我的问题是:如果serviceB.someMethodThatRunsInsertIntoDB()执行成功但dao1.anotherMethodThatRunsInsertIntoDB()抛出异常,则serviceB所做的更改不会回滚。如果dao1.anotherMethodThatRunsInsertIntoDB()发生异常,我需要回滚这些更改。我怎么能这样做?

// EDITED

spring-servlet.xml中的事务配置

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
    <property name="jpaDialect">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
    </property>
</bean>

如果一个dao使用EntityManager而另一个dao使用JdbcTemplate与DB交互是否相关?

// UPDATE - EntityManager配置

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="showSql" value="true" />
            <property name="generateDdl" value="true" />
        </bean>
    </property>

4 个答案:

答案 0 :(得分:2)

您需要传递rollbackFor参数以及已检查例外的类型。看起来Spring默认只在未经检查的异常上回滚。更多详情:Spring transaction: rollback on Exception or Throwable

答案 1 :(得分:1)

您需要在spring配置文件中使用<tx:annotation-driven/>来启用注释驱动的事务管理。

答案 2 :(得分:0)

这是因为您的dao1.anotherMethodThatRunsInsertIntoDB()调用不支持当前事务(ServiceA事务)。

您需要在ServiceB类中使用以下传播级别。

@Service
@Transactional(propagation = Propagation.REQUIRED)
public class ServiceB {

必需: Spring REQUIRED行为意味着如果当前bean方法执行上下文中已经打开的事务,将使用相同的事务。如果不存在,则创建一个新的。简而言之,这意味着如果内部(第二个事务)方法导致事务回滚,则外部(第一个事务)方法将无法提交并且还将回滚事务。

传播方式:通常,在事务范围内执行的所有代码都将在该事务中运行。但是,您可以选择在事务上下文已存在时执行事务方法时指定行为。例如,代码可以继续在现有事务中运行(常见情况);或者可以暂停现有交易并创建新交易。 Spring提供了EJB CMT中熟悉的所有事务传播选项。要阅读Spring中事务传播的语义,请参阅Transaction Propagation

编辑 注意:默认情况下,将事务设置为回滚状态的唯一例外是未经检查的异常(如RuntimeException)。如果您希望已检查的异常也将事务设置为回滚,则必须将它们配置为执行此操作, 例如。

@Service
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = YourCheckedException.class))
public class ServiceA {

注意: 正如我所注意到的,声明式事务管理是基于AOP的。这意味着Spring将事务bean包装到事务代理中,该代理负责启动和提交事务。这意味着必须由代理拦截方法调用才能成为事务性的。您需要在Spring配置文件中确保以下配置。

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

答案 3 :(得分:0)

我的第一个建议是在方法级别使用@Transactional注释,如果在类级别真的不需要它。

其次,尝试使用javax.transaction.Transactional注释而不是org.springframework.transaction.annotation.Transactional,Spring会自动处理传播。

您还需要在使用@Transactional之前启用事务管理,使用Spring Boot我们可以通过@EnableTransactionManagement标记Application类来完成此操作。

但是,如果您愿意,您也可以通过XML配置(<tx:annotation-driven />)完成此操作。请阅读http://docs.spring.io/spring-data/jpa/docs/1.11.0.M1/reference/html/#transactions了解详情