web-dev-qa-db-ja.com

@Transactionalと言うたびに、チェックされたすべての例外をロールバックします。

プログラマーはすべてのチェック済み例外をキャッチする必要があるため、問題が発生した場合はチェック済み例外をスローします。私はそれらの期待のいずれかにロールバックしたいと思います。すべての_rollbackFor=Exception.class_アノテーションに_@Transactional_を書き込むと、エラーが発生しやすくなるので、「_@Transactional_を書くときはいつでも、@Transactional(rollbackFor=Exception.class)」ということを春に伝えたいと思います。

カスタムアノテーションを作成できることはわかっていますが、それは不自然に思えます。

それで、春にチェックされた例外をどのように処理するべきかを伝える方法はありますかglobally

37
pihentagy

カスタムショートカットアノテーション

カスタムアノテーションを作成できることはわかっていますが、それは不自然に思えます。

いいえ、これはまさにカスタムアノテーションの使用例です。 Spring Referenceの Custom Shortcut Annotations からの引用は次のとおりです。

多くの異なるメソッドで@Transactionalを使用して同じ属性を繰り返し使用している場合、Springのメタアノテーションサポートにより、特定のユースケースにカスタムショートカットアノテーションを定義できます。

サンプルコード

ユースケースのサンプルアノテーションを次に示します。

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

次に、サービスやメソッドに@MyAnnotationで注釈を付けます(より適切な名前を考えます)。これは、デフォルトで機能する十分にテストされた機能です。なぜ車輪を再発明するのですか?

57

カスタムアノテーションを使用したアプローチは見た目は簡単ですが、実際に使用したくない場合は、カスタム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の通常の動作を期待する他の開発者を混乱させる可能性があることに注意してください。

17
axtavt

次のように、メソッド名に基づいてトランザクションアドバイスを設定できるようです((- Spring 2.0のドキュメント から))

どの例外タイプがトランザクションをロールバックにマークするかを正確に設定できます。以下は、チェックされたアプリケーション固有の例外タイプのロールバックを構成する方法を示す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>
3
oksayt

あなたはできる:

  • チェックされた例外をキャッチしてチェックされない例外にラップする-throw new RuntimeException(checkedException)
  • MethodInterceptor(または@AroundInvoke、またはその他の方法で春にアスペクトを作成する)を使用して、メソッドの周りにプロキシを作成し、<tx:annotation-driven />の前に実行するように宣言し、order="1"order="2"を指定して、そこでキャッチしてラップします。
3
Bozho