Spring @Transactional - 分離、伝播 質問する

Spring @Transactional - 分離、伝播 質問する

注釈内の分離および伝播パラメータを@Transactional実際の例で説明してくれる人はいますか?

基本的に、いつ、なぜデフォルト値を変更する必要があるのでしょうか?

ベストアンサー1

いい質問ですが、答えるのは簡単ではありません。

伝搬

トランザクションが互いにどのように関連しているかを定義します。一般的なオプション:

  • REQUIRED: コードは常にトランザクション内で実行されます。新しいトランザクションを作成するか、使用可能な場合は既存のトランザクションを再利用します。
  • REQUIRES_NEW: コードは常に新しいトランザクションで実行されます。現在のトランザクションが存在する場合は、それを中断します。

のデフォルト値は で@TransactionalありREQUIRED、多くの場合、これが望ましい値です。

分離

トランザクション間のデータ契約を定義します。

  • ISOLATION_READ_UNCOMMITTED: ダーティリードを許可します。
  • ISOLATION_READ_COMMITTED: ダーティリードは許可されません。
  • ISOLATION_REPEATABLE_READ: 同じトランザクションで行が 2 回読み取られた場合、結果は常に同じになります。
  • ISOLATION_SERIALIZABLE: すべてのトランザクションを順番に実行します。

マルチスレッド アプリケーションでは、レベルによってパフォーマンス特性が異なります。ダーティ リードの概念を理解すれば、適切なオプションを選択できると思います。

デフォルトはデータベースによって異なる場合があります。例えば、マリアDBそれはですREPEATABLE READ


ダーティ リードが発生する可能性がある例:

  thread 1   thread 2      
      |         |
    write(x)    |
      |         |
      |        read(x)
      |         |
    rollback    |
      v         v 
           value (x) is now dirty (incorrect)

したがって、妥当なデフォルト(そのようなデフォルトが要求される場合)は でありISOLATION_READ_COMMITTED、これは、伝播レベル と組み合わせて、実行中の他のトランザクションによってすでにコミットされた値のみを読み取ることができますREQUIRED。アプリケーションに他のニーズがある場合は、そこから作業を進めることができます。


provideServiceルーチンに入るときに常に新しいトランザクションが作成され、終了するときに完了する実際の例:

public class FooService {
    private Repository repo1;
    private Repository repo2;

    @Transactional(propagation=Propagation.REQUIRES_NEW)
    public void provideService() {
        repo1.retrieveFoo();
        repo2.retrieveFoo();
    }
}

代わりに を使用した場合REQUIRED、取引開いたままになるrollbackルーチンに入るときにトランザクションがすでに開かれていた場合。また、同じトランザクションで複数の実行が行われる可能性があるため、結果が異なる場合があることにも注意してください。


テストで動作を簡単に検証し、伝播レベルによって結果がどのように異なるかを確認できます。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:/fooService.xml")
public class FooServiceTests {

    private @Autowired TransactionManager transactionManager;
    private @Autowired FooService fooService;

    @Test
    public void testProvideService() {
        TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
        fooService.provideService();
        transactionManager.rollback(status);
        // assert repository values are unchanged ... 
}

伝播レベルは

  • REQUIRES_NEW:独自のサブトランザクションを作成したため、ロールバックされないfooService.provideService()ことが予想されます。

  • REQUIRED: すべてがロールバックされ、バッキング ストアは変更されていないと予想されます。

おすすめ記事