【问题标题】:Spring Transaction not rolling backSpring事务不回滚
【发布时间】:2017-03-03 14:01:42
【问题描述】:

我有这样的事情:

@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() 发生异常,我需要回滚这些更改。我该怎么做?

// 已编辑

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 交互,这是否相关?

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

【问题讨论】:

  • 除非您在 dao 方法中吞下异常,否则此代码应该可以工作。请添加您如何调用服务方法以及如何设置事务管理器。
  • 能否提供您的 Spring xml 配置文件?
  • 我编辑了帖子以添加事务xml配置。
  • 添加您的事务管理器配置,向您展示 JdbcTemplate 的使用。数据源配置和实体管理器配置。

标签: java spring rollback spring-transactions


【解决方案1】:

你需要在你的spring配置文件中使用&lt;tx:annotation-driven/&gt;来启用注解驱动的事务管理。

【讨论】:

    【解决方案2】:

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

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

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

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

    【讨论】:

      【解决方案3】:

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

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

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

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

      传播方式:通常,在事务范围内执行的所有代码都将在该事务中运行。但是,您可以选择指定在事务上下文已存在时执行事务方法时的行为。例如,代码可以在现有事务中继续运行(常见情况);或者可以暂停现有事务并创建新事务。 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" />
      

      【讨论】:

      • 春天不是默认的吗?
      • 我认为这是默认的。
      • 是的。但是使用默认设置,调用 secondService 方法时不会创建任何新的事务代理。我只管这个。
      • 我还是不明白,你基本上明确写了春天默认设置的相同的东西( Propagation.REQUIRED )
      • 是的,是的,我的配置中有
      【解决方案4】:

      你需要传递rollbackFor 参数和你检查的异常类型。默认情况下,弹簧回滚似乎只针对未经检查的异常。更多详情:Spring transaction: rollback on Exception or Throwable

      【讨论】:

      • 它抛出一个未经检查的异常,所以,我不需要 rollbackFor。
      猜你喜欢
      • 2012-03-10
      • 2018-07-15
      • 2020-03-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-21
      相关资源
      最近更新 更多