2011-06-27 6 views
3

を失う/このコードで休止状態:間接的にHibernate/JPAのメソッド呼び出しは、私は春/ JPA2を使用していたトランザクション

class A { 
    @Autowired 
    B b; 

    @RequestMapping("/test") 
    public void test(final HttpServletRequest r1, HttpServletResponse r2) throws ... { 

    b.inner(); // Works 

    b.outer(); // javax.persistence.TransactionRequiredException: 
       // no transaction is in progress ... :| 
} 

@Component 
class B { 
    @PersistenceContext 
    EntityManager em; 

    public void outer() { inner(); } 

    @Transactional 
    public void inner() { em.flush(); } 
} 

なぜ呼ばれるだけinner()は、間接的に取引を失うのですか?

答えて

5

http://static.springsource.org/spring/docs/current/reference/transaction.html#transaction-declarative-annotations

にスプリングのドキュメントを参照し、唯一の外部メソッドは、傍受されたプロキシを介して入ってくる呼び出し。つまり、ターゲットオブジェクトの別のメソッドを呼び出すターゲットオブジェクト内のメソッドを実際に呼び出すと、呼び出されたメソッドが@Transactionalでマークされていても、実行時に実際のトランザクションにつながることはありません。

自己呼び出しにもトランザクションをラップすると考えられる場合は、AspectJモード(下記の表のmode属性を参照)を使用することを検討してください。この場合、最初にプロキシは存在しません。代わりに、@Transactionalをどのような種類のメソッドでも実行時の振る舞いにするために、ターゲットクラスがウィーブされます(つまり、バイトコードが変更されます)。

(クラスA内側)@Autowired参照はB b、春AOPのトランザクション対応のプロキシでラップされています。

b.inner()が呼び出されると、トランザクション認識インスタンスで呼び出され、@Transactionalとマークされます。したがって、Spring管理トランザクションが開始されます。 b.outer()が呼び出される

は、それがトランザクション対応のインスタンスにもありますが、それは、ない@Transactionalです。したがって、Spring管理トランザクションはで、は開始していません。

あなたはinner()への呼び出しがトランザクション対応のプロキシを経由しないあるouter()の呼び出し内にあると、それが直接起動されています。 this.inner()と同じです。プロキシを介さずに直接呼び出すので、Springのトランザクション認識のセマンティクスはありません。

トランザクションが開始されていないため、TransactionRequiredExceptionになります。可能な解決策は、方法を作ることを含む。outer()@Transactional

@Transactional 
    public void outer() { inner(); } 

またはクラス全体を作成する@Transactional

@Transactional 
@Component 
class B { 
    @PersistenceContext 
    EntityManager em; 
+0

私の目標は、バックグラウンドプログラムを作成し、毎回小さなビットをコミットすることでした。したがって、単なるトランザクションとしてouter()に注釈を付けることは私の意図ではありません。私はプロキシモードをアスペクトモードに変更していません。 ありがとう! – Cojones

+0

'B.outer()'のロジックが 'Binner()'の前に発生する必要があるが、トランザクション/持続性に関係しない場合は、あなたのパーシスタンス層クラス(DAL/DAOなど)に属していない可能性があります。中間オブジェクトを使用しても問題を分離するようにデザインをリファクタリングすることを検討してください。 'Object intermediate = b.outer(); b.inner(中間); '。そしてリファクタリングして、それはもはやあなたのパーシスタンス層クラスのメンバーではありません。 'Object intermediate = someOtherUtilityOrSupportClassInstance.outer(); b.inner(中間); '。 – Dan

+0

私は今LTWに切り替えましたが、今はどんな呼び出しでもトランザクションが発生しません:(すべての設定は Cojones

0

トランザクションコンテキストは、Spring Beanの全ライフスパンのスコープにわたって持続します。 @Transactional表記は、コンポーネント全体の範囲を持って、あなたは、内側と外側のメソッドは、仕事の個々のユニットを達成する必要があり@Transactional例えば

@Transactional 
@Component 
class B { 
    @PersistenceContext 
    EntityManager em; 

    public inner() { } 
    public outer() { } 
} 

としてあなた@Componentに注釈を付ける必要があります。いくつかのヘルパー関数が必要な場合や、それがうまくいく場合は、トランザクション境界を必要とする作業単位には各メソッドのスコープを設定する必要があります。 @Transactional http://static.springsource.org/spring/docs/3.0.x/reference/transaction.html(デフォルト)プロキシモードで

関連する問題