10

私が実装した以下のサービス方法:updateと呼ばれ、私は別のサービスメソッドを使用してこのメ​​ソッドの内部春のネストされたトランザクション私の春のブートプロジェクトで

@Transactional 
public boolean validateBoard(Board board) { 
    boolean result = false; 
    if (inProgress(board)) { 
     if (!canPlayWithCurrentBoard(board)) { 
      update(board, new Date(), Board.AFK); 
      throw new InvalidStateException(ErrorMessage.BOARD_TIMEOUT_REACHED); 
     } 
     if (!canSelectCards(board)) { 
      update(board, new Date(), Board.COMPLETED); 
      throw new InvalidStateException(ErrorMessage.ALL_BOARD_CARDS_ALREADY_SELECTED); 
     } 
     result = true; 
    } 
    return result; 
} 

@Transactional(propagation = Propagation.REQUIRES_NEW) 
public Board update(Board board, Date finishedDate, Integer status) { 
    board.setStatus(status); 
    board.setFinishedDate(finishedDate); 

    return boardRepository.save(board); 
} 

私はコミットする必要がありますvalidateBoardメソッドで開始された所有者トランザクションとは独立してupdateメソッドのデータベースに変更されます。現在、例外が発生した場合、変更はすべてロールバックされます。

@Transactional(propagation = Propagation.REQUIRES_NEW)であっても動作しません。

Springで正しくこれを行い、ネストされたトランザクションを許可する方法はありますか?

+4

あなたは同じクラス内のメソッドを呼び出しているので、Springは呼び出しを傍受してトランザクションプロキシを適用できません( 'REQUIRES_NEW'伝播は無視されます)。 'update'メソッドを別のSpring beanに移行する必要があります。 –

+0

ありがとうございます。 – alexanoid

答えて

8

このドキュメントはあなたの問題をカバー - http://docs.spring.io/autorepo/docs/spring/current/spring-framework-reference/html/transaction.html(デフォルト)プロキシモードで

、唯一の外部メソッドは、プロキシ経由で入ってくるが傍受されて呼び出します。つまり、ターゲットオブジェクトの別のメソッドを呼び出すターゲットオブジェクト内のメソッドを実際に呼び出すと、呼び出されたメソッドが@Transactionalでマークされていても、実行時に実際のトランザクションにはなりません。また、プロキシは、初期化コード(@PostConstruct)にこの機能を依存させないように、期待される動作を提供するために完全に初期化する必要があります。

しかし、あなたの問題は、同じproxy.Itの自己呼び出し内部の別のメソッドからメソッドの呼び出しです

1

updateのトランザクション注釈は、同じクラスのメソッドから呼び出された場合、Springトランザクションインフラストラクチャによって考慮されません。 Springのトランザクションインフラストラクチャの仕組みの詳細については、thisを参照してください。

0

AspectJのモードに切り替えるためのオプションがあります。 あなたのケースでは、別のサービスの中でメソッドを動かすことなく簡単に修正することができます(自己呼び出しを避けるために、あるサービスを別のサービスに移動するために別のサービスを作成する必要があるのはなぜですか?メソッドは現在のクラスから直接ではなく、スプリングコンテナから取得します。この場合、self-invocatioではなく、トランザクションでプロキシの2番目のメソッドを呼び出します。

この原則は、トランザクションプロキシだけでなく、自己呼び出しが必要な場合に、任意のプロキシオブジェクトに役立ちます。プロキシオブジェクトcontext.getBean(SomeService.class).methodTwo(object);コンテナリターンを呼ぶのですし、このプロキシにあなたが取引にmethodTwo(...)を呼び出すことができます

@Service 
class SomeService ..... { 
    -->> @Autorired 
    -->> private ApplicationContext context; 
    -->> //or with implementing ApplicationContextAware 

    @Transactional(any propagation , it's not important in this case) 
    public boolean methodOne(SomeObject object) { 
     ....... 
     -->> here you get a proxy from context and call a method from this proxy 
     -->>context.getBean(SomeService.class). 
      methodTwo(object); 
     ...... 
    } 

    @Transactional(any propagation , it's not important in this case)public boolean 
    methodTwo(SomeObject object) { 
    ....... 
    } 
} 

関連する問題