java Spring事务不回滚

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/40173587/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 04:59:01  来源:igfitidea点击:

Spring Transaction not rolling back

javaspringrollbackspring-transactions

提问by user2466251

I have something like this:

我有这样的事情:

@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();
     }

}

My problem is: if serviceB.someMethodThatRunsInsertIntoDB()executes sucessfully but dao1.anotherMethodThatRunsInsertIntoDB()throw an exception, the changes made by serviceBare not rolled back. I need to rollback those changes in case an exception occur in dao1.anotherMethodThatRunsInsertIntoDB(). How can I do this?

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

// EDITED

// 编辑

Transaction configuration in spring-servlet.xml

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>

Is it relevant if one dao uses an EntityManager and the other dao uses JdbcTemplate to interact with DB?

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

//UPDATE -- EntityManager configuration

//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>

回答by freakman

you need to pass rollbackForparameter with type of your checked exception. It seems that spring rollbacks only on unchecked exceptions by default. More details: Spring transaction: rollback on Exception or Throwable

您需要传递rollbackFor带有已检查异常类型的参数。似乎默认情况下,spring 仅在未检查的异常上回滚。更多详细信息:Spring 事务:在 Exception 或 Throwable 上回滚

回答by Amritanjali semwal

you need to use <tx:annotation-driven/>inside you spring configuration file to enable the annotation driven transaction management.

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

回答by Naresh Joshi

My first suggestion is to use @Transactionalannotation on method level if it is really not needed on class level.

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

Second thing, try use javax.transaction.Transactionalannotation instead of org.springframework.transaction.annotation.Transactional, Spring will automatically handle the propagation.

第二件事,尝试使用javax.transaction.Transactional注解而不是 org.springframework.transaction.annotation.Transactional,Spring 会自动处理传播。

You also need to enable transaction management before using @Transactional, Using Spring Boot we can simply do that by marking Application class by @EnableTransactionManagement.

您还需要在使用之前启用事务管理@Transactional,使用 Spring Boot 我们可以通过将 Application 类标记为 来简单地做到这一点@EnableTransactionManagement

However, you can surely do this by XML configuration (<tx:annotation-driven />) as well if you want to. Read http://docs.spring.io/spring-data/jpa/docs/1.11.0.M1/reference/html/#transactionsfor more details

但是,<tx:annotation-driven />如果您愿意,您当然也可以通过 XML 配置 ( )来做到这一点。阅读http://docs.spring.io/spring-data/jpa/docs/1.11.0.M1/reference/html/#transactions了解更多详情

回答by Ye Win

It's because your dao1.anotherMethodThatRunsInsertIntoDB() call does not support current transaction (ServiceA transaction).

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

You need to use below propagation level in your ServiceB class.

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

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

REQUIRED:Spring REQUIRED behavior means that the same transaction will be used if there is an already opened transaction in the current bean method execution context. Create a new one if none exists. In short this means that if an inner(2nd Transaction) method causes a transaction to rollback, the outer(1st Transaction) method will fail to commit and will also rollback the transaction.

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

Propagation Means:Typically, all code executed within a transaction scope will run in that transaction. However, you have the option of specifying the behavior in the event that a transactional method is executed when a transaction context already exists. For example, code can continue running in the existing transaction (the common case); or the existing transaction can be suspended and a new transaction created.?Spring offers all of the transaction propagation options familiar from EJB CMT. To read about the semantics of transaction propagation in Spring, see Transaction Propagation

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

Edited
Note:The only exceptions that set a transaction to rollback state by default are the unchecked exceptions (like RuntimeException). If you want checked exceptions to also set transactions to rollback you must configure them to do so, eg.

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

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

Note:As I noticed, declarative transaction management is AOP based. This means that Spring wraps the transactional beans into a transactional proxy, which takes care of starting and committing transactions. This means that the method call must be intercepted by the proxy in order to be transactional. You need to make sure below config had in your Spring configuration file.

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

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