Java 每当我说@Transactional 时,回滚每个已检查的异常

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3701376/
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-08-14 03:39:20  来源:igfitidea点击:

Rollback on every checked exception, whenever I say @Transactional

javaspringjpajpa-2.0

提问by pihentagy

Since the programmer is forced to catch all checked exception, I to throw checked exception in case of any problem. I would like to rollback on any of those expections. Writing rollbackFor=Exception.classon every @Transactionalannotation is very error-prone, so I would like to tell spring, that: "whenever I write @Transactional, I mean @Transactional(rollbackFor=Exception.class)".

由于程序员被迫捕获所有已检查的异常,因此如果出现任何问题,我将抛出已检查的异常。我想回滚这些期望中的任何一个。rollbackFor=Exception.class在每一个@Transactional注解上写都是很容易出错的,所以我想告诉spring,“每当我写的时候@Transactional,我的意思是@Transactional(rollbackFor=Exception.class)”。

I know, that I could create a custom annotation, but that seems unnatural.

我知道,我可以创建自定义注释,但这似乎不自然。

So is there a way to tell spring how it should handle checked excpetions globally?

那么有没有办法告诉 spring 它应该如何处理全局检查的异常?

采纳答案by Sean Patrick Floyd

Custom Shortcut Annotations

自定义快捷方式注释

I know, that I could create a custom annotation, but that seems unnatural.

我知道,我可以创建自定义注释,但这似乎不自然。

No, this is exactly the use case for a Custom Annotation. Here's a quote from Custom Shortcut Annotationsin the Spring Reference:

不,这正是自定义注释的用例。这是Spring 参考中自定义快捷方式注释的引用:

If you find you are repeatedly using the same attributes with @Transactional on many different methods, then Spring's meta-annotation support allows you to define custom shortcut annotations for your specific use cases.

如果您发现在许多不同的方法上重复使用带有 @Transactional 的相同属性,那么 Spring 的元注释支持允许您为特定用例定义自定义快捷注释。

Sample Code

示例代码

And here's a sample annotation for your use case:

这是您的用例的示例注释:

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

Now annotate your services and / or methods with @MyAnnotation(you'll think of a better name). This is well-tested functionality that works by default. Why re-invent the wheel?

现在用@MyAnnotation(你会想到一个更好的名字)来注释你的服务和/或方法。这是经过充分测试的功能,默认情况下有效。为什么要重新发明轮子?

回答by Bozho

You can:

你可以:

  • catch and wrap the checked exception into an unchecked exception - throw new RuntimeException(checkedException)
  • create a proxy around the method, using MethodInterceptor(or @AroundInvoke, or any other means to create aspects in spring), declare it to be executed before the <tx:annotation-driven />by specifying order="1"and order="2"and catch and wrap there.
  • 捕获已检查的异常并将其包装到未检查的异常中 - throw new RuntimeException(checkedException)
  • 围绕该方法创建一个代理,使用MethodInterceptor(或@AroundInvoke,或任何其他方式在 spring 中创建方面),<tx:annotation-driven />通过指定order="1"andorder="2"并在那里捕获和包装来声明它在 之前执行。

回答by oksayt

Looks like you can configure a transactional advice based on method name like this: (from the Spring 2.0 docs)

看起来您可以像这样根据方法名称配置事务性建议:(来自Spring 2.0 文档

Exactly which Exception types mark a transaction for rollback can be configured. Find below a snippet of XML configuration that demonstrates how one would configure rollback for a checked, application-specific Exception type.

可以配置究竟哪些异常类型将事务标记为回滚。在下面找到一段 XML 配置片段,该片段演示了如何为已检查的、特定于应用程序的异常类型配置回滚。

<tx:advice id="txAdvice" transaction-manager="txManager">
    <tx:attributes>
      <tx:method name="get*" read-only="false" rollback-for="NoProductInStockException"/>
      <tx:method name="*"/>
    </tx:attributes>
</tx:advice>

回答by axtavt

Approach with custom annotation looks good and straightforward, but if you actually don't want to use it, you can create a custom TransactionAttributeSourceto modify interpretation of @Transactional:

使用自定义注释的方法看起来不错且简单明了,但如果您实际上不想使用它,您可以创建一个自定义TransactionAttributeSource来修改对 的解释@Transactional

public class RollbackForAllAnnotationTransactionAttributeSource 
    extends AnnotationTransactionAttributeSource {
    @Override
    protected TransactionAttribute determineTransactionAttribute(
            AnnotatedElement ae) {
        TransactionAttribute target = super.determineTransactionAttribute(ae);
        if (target == null) return null;
        else return new DelegatingTransactionAttribute(target) {
            @Override
            public boolean rollbackOn(Throwable ex) {
                return true;
            }
        };
    }
}

And instead of <tx:annotation-driven/>you configure it manually as follows (see source of AnnotationDrivenBeanDefinitionParser):

而不是<tx:annotation-driven/>您手动配置它如下(见来源AnnotationDrivenBeanDefinitionParser):

<bean id = "txAttributeSource"
    class = "RollbackForAllAnnotationTransactionAttributeSource" />

<bean id = "txInterceptor"
    class = "org.springframework.transaction.interceptor.TransactionInterceptor">
    <property name = "transactionManagerBeanName" value = "transactionManager" />
    <property name = "transactionAttributeSource" ref = "txAttributeSource" />
</bean>

<bean
    class = "org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor">
    <property name="transactionAttributeSource" ref = "txAttributeSource" />
    <property name = "adviceBeanName" value = "txInterceptor" />
</bean>

Also you need <aop:config/>or <aop:aspectj-autoproxy />.

您还需要<aop:config/><aop:aspectj-autoproxy />

However note that such overrides may be confusing for other developers who expect a normal behaviour of @Transactional.

但是请注意,对于其他期望@Transactional.