515

実世界の例を介して、注釈の分離伝播のパラメーターが何であるかを誰かが説明できますか?@Transactional

基本的に、いつ、なぜデフォルト値を変更することを選択する必要があるのか​​.

4

10 に答える 10

500

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

伝搬

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

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

のデフォルト値@TransactionalREQUIREDです。多くの場合、これが必要です。

隔離

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

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

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

デフォルトは、異なるデータベース間で異なる場合があります。例として、MariaDBの場合は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複数の実行が同じトランザクションに参加する可能性があるため、 a の結果が異なる可能性があることにも注意してください。


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

@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: すべてがロールバックされ、バッキング ストアが変更されていないことが予想されます。

于 2011-12-13T14:34:20.917 に答える
24

Read Uncommited実際にはACID準拠していないため、使用することはほとんどありません。Read Commmitedデフォルトの出発点として適しています。Repeatable Readおそらく、レポート、ロールアップ、または集計のシナリオでのみ必要です。postgres を含む多くの DB は実際には Repeatable Read をサポートしていないことに注意してくださいSerializable。代わりに使用する必要があります。Serializable他のものとは完全に独立して発生する必要があることがわかっている場合に役立ちます。synchronizedJavaのように考えてください。シリアライズ可能はREQUIRES_NEW伝播と密接に関連しています。

REQUIRES「サービス」レベルの関数だけでなく、UPDATE または DELETE クエリを実行するすべての関数にも使用します。SELECT のみを実行する DAO レベルの関数SUPPORTSの場合、TX が既に開始されている場合 (つまり、サービス関数から呼び出されている場合) に参加する which を使用します。

于 2011-12-13T15:13:14.593 に答える