Spring: 检查异常时自动回滚

Spring: automatic rollback on checked exceptions

配置 Spring 以在非 RuntimeExceptions 上回滚的一种方法是在服务 classes 上使用 @Transactional(rollbackFor=...) 注释。这种方法的问题是我们需要为几乎所有的服务定义 (rollbackFor=...) classes 这看起来确实是多余的。


我的问题:是否有任何方法可以为 Spring 事务管理器配置默认行为,以便在非 RuntimeException 发生时回滚,而无需在每个 @Transactional 注释上声明它。类似于在 EJB 中的异常 class 上使用 @ApplicationException(rollback=true) 注释。

您不能使用 @Transactional 在应用程序级别执行此操作,但您可以:

变体 1 : 扩展 @Transactional 注释并将其作为 rollbackfor 的默认值。但是只设置你需要的 rollbackFor unchecked exceptions。有了这个你可以控制回滚只在你确定的情况下,并避免复制过去的@Transactional(rollbackFor =MyCheckedException.class)

喜欢:

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Transactional(rollbackFor=MyCheckedException.class)
public @interface TransactionalWithRollback {
}

并使用此注释代替标准的@Transactional。

变体 2: 您可以从 AnnotationTransactionAttributeSource 创建扩展并覆盖方法 determineTransactionAttribute:

protected TransactionAttribute  determineTransactionAttribute(AnnotatedElement ae)
//Determine the transaction attribute for the given method or class.

TransactionAttribute 看TransactionAttribute api ,有个方法

boolean rollbackOn(Throwable ex) Should we roll back on the given exception?

protected TransactionAttribute determineTransactionAttribute(
    AnnotatedElement ae) {
    return new DelegatingTransactionAttribute(target) {
        @Override
        public boolean rollbackOn(Throwable ex) {
           return (check is exception type as you need for rollback );
       }
};

}

第二种方法不如第一种好,因为它对于事务管理器来说确实是全局的。最好使用自定义注释,因为您可以控制它仅适用于 methods/classes 您真正需要它的地方。但是,如果您在任何情况下都需要它,请使用第二个变体,这将是您默认的跨国行为。

这个配置解决了它:

@Configuration
public class MyProxyTransactionManagementConfiguration extends ProxyTransactionManagementConfiguration {

    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public TransactionAttributeSource transactionAttributeSource() {
        return new AnnotationTransactionAttributeSource() {

            @Nullable
            protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
                TransactionAttribute ta = super.determineTransactionAttribute(element);
                if (ta == null) {
                    return null;
                } else {
                    return new DelegatingTransactionAttribute(ta) {
                        @Override
                        public boolean rollbackOn(Throwable ex) {
                            return super.rollbackOn(ex) || ex instanceof Exception;
                        }
                    };
                }
            }
        };
    }
}

这是与 类似的方法,即全局更改默认值,但对 Spring 的配置进行尽可能少的更改,并且仍然可以根据需要自定义回滚规则像往常一样的方法(使用 rollbackFornoRollbackFor 等)。

这只需为 Exception.class 添加默认的 RollbackRule 即可实现。由于规则根据异常 class 层次结构具有优先级(最具体的异常 class 适用的规则优先),如果注释上没有定义其他规则,则新规则基本上具有最低的优先级。

@Configuration
public class MyTransactionManagementConfiguration {
  /**
   * Note: This custom config does NOT recognize {@code javax.transaction.Transactional} annotations in contrast to
   * the original Spring behaviour. Check the original {@code AnnotationTransactionAttributeSource} source code for an idea how to add that.
   *
   * @see AnnotationTransactionAttributeSource#AnnotationTransactionAttributeSource(boolean)
   */
  @Bean
  @Primary
  @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
  public TransactionAttributeSource transactionAttributeSourceWithDefaultRollBackForAllExceptions() {
    return new AnnotationTransactionAttributeSource(
        new SpringTransactionAnnotationParser() {
          
          @Override
          protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
            RuleBasedTransactionAttribute rbta = (RuleBasedTransactionAttribute) super.parseTransactionAnnotation(attributes);
            List<RollbackRuleAttribute> rules = new ArrayList<>(rbta.getRollbackRules());
            rules.add(new RollbackRuleAttribute(Exception.class));
            rbta.setRollbackRules(rules);
            return rbta;
          }

        }
    );
  }
}