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 的配置进行尽可能少的更改,并且仍然可以根据需要自定义回滚规则像往常一样的方法(使用 rollbackFor
、noRollbackFor
等)。
这只需为 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;
}
}
);
}
}
配置 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;
}
};
}
}
};
}
}
这是与 rollbackFor
、noRollbackFor
等)。
这只需为 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;
}
}
);
}
}