2011-10-25 9 views
6

私は最も奇妙なことが起こっていると私は理由を理解できません。これを記述するための最良の方法は、簡単な例を提供することである。この特定のケースでは既に捕獲された後の例外プロポゲート

@Service 
@Transactional 
public class Foo{ 
    public ModelAndView delete(@ModelAttribute("abc") Long id) { 
     ModelAndView mav = new ModelAndView(); 
     try { 
      getDaoService().delete(id); //Calls Bar.delete() 
     } catch (final Exception e) { 
      // Add a custom error message to the mav for the user to see 
      mav.getModelMap().addAttribute(blah, blah); 
     } 
     return mav; 
    } 
} 

@Service 
@Transactional 
public class Bar { 
    public void delete(final E entity) throws HibernateException { 
     if (null != entity) { 
      try { 
       sessionFactory.getCurrentSession().delete(entity); 
      } finally { 
       sessionFactory.getCurrentSession().flush(); 
      } 
     } 
    } 
} 

を、私は、制約違反(ORA-02292)を持つオブジェクトを削除しようとしています。私はこのために削除が失敗することを期待しています。削除が失敗すると、適切なカスタムメッセージをユーザーに表示します。代わりに、ユーザーにカスタムメッセージを表示することができるという

は、呼び出しが画面に次の失敗と表示されます。

org.springframework.transaction.UnexpectedRollbackException:それはマークされているため、トランザクションがロールバックさ ロールバックのみ

デバッガを使用すると、エラーが適切に検出され、ModelAndViewオブジェクトにカスタムメッセージが含まれていることがわかります。だから、なぜそれが捕まえられて対処された後に例外がスローされているのかわからない。誰がなぜこれが起こっているのかについての洞察を持っていますか?

答えて

5

@Transactionalアノテーションでは、noRollbackForClassName属性を使用して、特定の例外が原因でトランザクションをロールバックするかどうかを指定できます。あなたはこれに似ています。

@Service 
@Transactional(noRollbackForClassName = "java.lang.Exception") 
public class YourClass { 
    ... 
} 

しかし、良い練習そのないため、単にnoRollbackForClassName = "java.lang.Exception"を言うことは、それが任意の例外(またはそのサブクラス)のためにロールバックしないという意味だろうことに注意してください。

まず、実際に例外が実際にスローされたことを確認してから(e.getClass().getName()を印刷してもよい)、そのクラス名をnoRollbackForClassName値として設定します。

delete()を試行中に例外がスローされた場合、現在のトランザクションはロールバックのみとして自動的にマークされ、コミットしようとすると例外がスローされるため、これが起こります。 。これを渡す方法は、この特定の例外がロールバックを引き起こしてはならないことを明示的に述べることです。

+0

素晴らしい、魅力的なように働いた!ありがとう!!! – user973479

1

例外はBar#deleteでスローされ、Foo#deleteで捕捉されます。 Bar#deleteに@Transactionalアノテーションがあり、例外が捕捉される前に渡されます。この内部トランザクションは外部トランザクションに関与しているため、トランザクション全体がロールバック対象としてマークされます。

これを避けるには、Bar#deleteの@Transactionalアノテーションを削除することができます。このメソッドは、すでに他のトランザクションのスコープ内で呼び出されています。

+0

素晴らしい、魅力的なように働いた!ありがとう!!! – user973479

4

例外がスローされると、Springは内部的にtxをロールバック専用としてマークするため、問題があります。これは、Javaの例外処理とはまったく別物です。あなたは、いくつかのオプションがあります。

  • あなたの予想される例外がRuntimeExceptionを拡張し、例外をスローしていないことを確認します。 Springは、タイプがRuntimeExceptionsee this page、セクション10.5.3)のときにのみtxをロールバックします。 HibernateException extends RuntimeExceptionです。そのため、ロールバックマーカーが取得されています。
  • トランザクションメソッドを独自のクラスに移動し、@Transactional(propagation=Propagation.REQUIRES_NEW)を使用して注釈を付けることによって、各トランザクションを独自のトランザクションで実行します。その後、それぞれの呼び出しは独自のtxで実行され、全体のtxには影響しません。
  • 上記のnoRollbackForClassNameスタイルのvenushkaを使用してください。しかし、言及された理由のため、慎重に使用してください。
+0

例外がRuntimeExceptionを拡張するとき、私は何ができますか? – sebnukem

0

プロパティを追加します"globalRollbackOnParticipationFailure"をhibernateTransactionManagerビーン定義に次のように。

<bean id="hibernateTransactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> 
    <property name="sessionFactory" ref="hibernateSessionFactory" /> 
    **<property name="globalRollbackOnParticipationFailure" value="false" />** 
</bean> 
関連する問題