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

时间:2010-09-13 14:34:16

标签: java spring jpa jpa-2.0

由于程序员被强制捕获所有已检查的异常,因此我会在出现任何问题时抛出已检查的异常。我想回滚任何这些期望。在每个rollbackFor=Exception.class注释上写@Transactional非常容易出错,所以我想告诉春天:“每当我写@Transactional时,我的意思是@Transactional(rollbackFor=Exception.class)”。< / p>

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

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

4 个答案:

答案 0 :(得分:52)

自定义快捷方式注释

  

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

不,这正是自定义注释的用例。以下是Spring Reference中Custom Shortcut Annotations的引用:

  

如果您发现您反复使用   与...相同的属性   @Transactional对很多不同   方法,然后是Spring的元注释   支持允许您定义自定义   特定的快捷方式注释   用例。

示例代码

这是一个用例的示例注释:

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

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

答案 1 :(得分:15)

使用自定义注释的方法看起来很好而且直截了当,但如果您实际上不想使用它,则可以创建自定义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;
            }
        };
    }
}

而不是<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>

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

但是请注意,对于期望@Transactional的正常行为的其他开发者而言,此类覆盖可能会造成混淆。

答案 2 :(得分:3)

你可以:

  • 捕获并将已检查的异常包装到未经检查的异常 - throw new RuntimeException(checkedException)
  • 围绕方法创建代理,使用MethodInterceptor(或@AroundInvoke或其他任何方式在spring中创建方面),通过指定{来声明它在<tx:annotation-driven />之前执行{1}}和order="1"并抓住并包裹在那里。

答案 3 :(得分:3)

看起来您可以根据方法名称配置事务建议,如下所示: (来自the Spring 2.0 docs

  

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

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