春のトランザクション伝播特性をやることが難しいですか?この1を見てくださいすることは十分にあります

春のトランザクション伝播特性をやることが難しいですか?この1を見てくださいすることは十分にあります

スキルを書いて、著者はまだ浅く、間違った場合は、寛大さを指摘してください、感謝するでしょう

唯一の理論と実践は、その後、マスターはそれを忘れて数日と推定、特に強くはありませんしていなかった知っているならば、彼らは何かを学んだ適用することを学び、その後、我々は練習の春のトランザクション伝播特性を学ぶために一緒に来ます。

伝播特性

伝播プロパティが定義されている他の取引方法と、トランザクション処理の振る舞いの方法としては、遭遇した定義され、7つの行動の合計は、次のように

伝達性 説明
PROPAGATION_REQUIRED 0 現在のトランザクション、そうでない場合は、新しいトランザクションをサポートしています
PROPAGATION_SUPPORTS 1 業務を実行するためではない方法がない場合は、現在のトランザクションをサポートしています
PROPAGATION_MANDATORY 2 現在のトランザクションが例外をスローしない場合は、現在のトランザクションをサポートしています
PROPAGATION_REQUIRES_NEW 3 現在のトランザクションがあるかどうかにかかわらず、新しいトランザクションを開始します
PROPAGATION_NOT_SUPPORTED 4 これは、現在のトランザクションが存在する場合、この保留中のトランザクションは、トランザクション・モードで実行されません、トランザクションをサポートしていません。
PROPAGATION_NEVER 5 例外をスローするトランザクションがある場合は、トランザクションをサポートしていません。
PROPAGATION_NESTED 6 現在のトランザクションは、現在のトランザクション内に存在する場合、その後、新しいトランザクションを開始します

実際には、単に言葉の概念を見て、我々はあなたに各伝播属性の下の行動の具体例を示し、この時、各スプレッドの役割を非常に簡単に説明されています。

私たちのために、それはちょうど私たちが他の手配をすることなく、トランザクションの効果を証明するように、私たちは、内部のメモリの役割であるH2データベースを使用しているデモは、我々は新しいテーブルを作成します。上の次の文schema.sql私たちが始めたときである、SpringBootプログラムが自動的にメモリにこのような表を作成することができ、ドキュメント、。

CREATE TABLE FOO (ID INT IDENTITY, BAR VARCHAR(64));

复制代码

プレゼンテーションの前に、我々は2つのクラスを定義しますFooServiceBarService私たちは、使用BarServiceメソッド呼び出しの内側FooService方法。

環境の準備

トランザクションが実証する前に、実際には、それは次のような状況に分けることができ、順列と組み合わせに応じて、我々は以下の8例を描くことができます

  • 発信者:トランザクションかどうか
  • 発信者:例外があります
  • 呼び出し先:**取引配置で(これは伝播特性によって制御されている)があります**組み合わせはそうではありません
  • 呼び出し先:例外があります
呼び出し側が業務を持っています 呼び出し側は異常あり 呼び出し側は異常あり
持っています 持っています 持っています
持っています 持っています ノー
持っています ノー 持っています
持っています ノー ノー
ノー 持っています 持っています
ノー 持っています ノー
ノー ノー 持っています
ノー ノー ノー

Exceptionクラス

これはRollbackException私たち自身の定義の珍しいクラスであります

@Service
public class BarServiceImpl implements BarService{
    @Autowired
    private FooService fooService;

 	// PROPAGATION_REQUIRED演示 无事务
    @Override
    public void testRequiredNoTransactional() throws RollbackException {
        fooService.testRequiredTransactional();
    }
}

复制代码

呼び出し側

BarService取引を持つ2つの方法で、1の定義は、トランザクションはなしです

// 有事务
@Override
@Transactional(rollbackFor = Exception.class)
public void hasTransactional() throws RollbackException {

}

// 无事务
@Override
public void noTransactional() throws RollbackException {
    
}

复制代码

上記に定義したその後、我々は状況ロシアの8種類に基づいて、トランザクションの伝播特性を学びます。

PROPAGATION_REQUIRED

この伝播特性では、トランザクションはトランザクションと、発信者かどうかに依存し、発信者が新規であるかどうかです。

あなたはこの事実の伝播特性の特性を理解したい二つの例には、我々はこのような状況の8種類を発揮十分です

呼び出し側が業務を持っています 呼び出し側は異常あり 呼び出し側は異常あり
ノー ノー 持っています
持っています 持っています ノー
  • クエリがデータを挿入することができないならば、我々は、呼び出し側の場合に例外をスロー最初のケースでは、それは彼らの新しいビジネスの取引せずに、発信者の発信者を示しています。
  • クエリがデータを挿入することができないならば、我々は、呼び出し側の場合に例外をスロー二例の場合、それは、呼び出し側で呼び出し元がトランザクションに現在のトランザクションに参加している示しています。

のは、呼び出し側のクラスのメソッドの例を見てみましょう。

@Service
public class FooServiceImpl implements FooService {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    // REQUIRED传播属性-被调用者有异常抛出
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void testRequiredHasException() throws RollbackException {
        jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ("+Global.REQUIRED_HAS_EXCEPTION+")");
        throw new RollbackException();
    }

    // REQUIRED传播属性-被调用者无异常抛出
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void testRequiredNoException() throws RollbackException {
        jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ("+Global.REQUIRED_NO_EXCEPTION+")");
    }
}
复制代码

次は、呼び出し元のメソッドの例を見て

@Service
public class BarServiceImpl implements BarService{
    @Autowired
    private FooService fooService;

    // 有事务
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void hasTransactional() throws RollbackException {
        // 调用者有事务,抛异常  被调用者无异常
        fooService.testRequiredNoException();
        throw new RollbackException();
    }

    // 无事务
    @Override
    public void noTransactional() throws RollbackException {
        // 调用者无事务,不抛异常  被调用者有异常
        fooService.testRequiredHasException();
    }
}

复制代码

この時点で、我々はときに、プログラムの呼び出し照会しました

String noException = Global.REQUIRED_NO_EXCEPTION;
String hasException = Global.REQUIRED_HAS_EXCEPTION;

try {
    barService.noTransactional();
}catch (Exception e){
    log.info("第一种情况 {}",
            jdbcTemplate
                    .queryForObject("SELECT COUNT(*) FROM FOO WHERE BAR='"+hasException+"'", Long.class));
}

try {
    barService.hasTransactional();
}catch (Exception e){
    log.info("第二种情况 {}",
            jdbcTemplate
                    .queryForObject("SELECT COUNT(*) FROM FOO WHERE BAR='"+noException+"'", Long.class));
}

复制代码

ログアウトの表示印刷

2019-10-16 13:02:04.142  INFO 11869 --- [           main] c.e.t.t.TransactionApplication           : 第一种情况 0
2019-10-16 13:02:04.143  INFO 11869 --- [           main] c.e.t.t.TransactionApplication           : 第二种情况 0
复制代码

我々は、データがロールバックされていることを示すために、対応するデータを特定していないことがわかります。この時点で、私たちは、その文が考えを理解する必要があり、現在のトランザクションをサポートし、そうでない場合は、新しいトランザクション

PROPAGATION_SUPPORTS

呼び出し側は、呼び出し元に完全に依存して業務を、持って、トランザクションが存在し、呼び出し側は、トランザクションが存在し、呼び出し元はトランザクションは、トランザクションされていないではありません。

次に、我々は、上記の2つの例で実証します

呼び出し側が業務を持っています 呼び出し側は異常あり 呼び出し側は異常あり
ノー ノー 持っています
持っています 持っています ノー
  • 最初のケース:まだ取引上のデータを照会する場合場合は、発信者が業務を持っていないことを示す、ロールバックされていない、呼び出し元を投げました
  • 第二の場合:発信者がトランザクションに二つの方法でデータかどうかを見つける、例外ケースをスロー

次の例はまだ示してい

呼び出し側が、@Transactional中に注釈propagation交換するために、プロパティPropagation.SUPPORTS

// SUPPORTS传播属性-被调用者有异常抛出
@Override
@Transactional(rollbackFor = Exception.class,propagation = Propagation.SUPPORTS)
public void testSupportsHasException() throws RollbackException {
    jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ('"+Global.SUPPORTS_HAS_EXCEPTION+"')");
    throw new RollbackException();
}

// SUPPORTS传播属性-被调用者无异常抛出
@Override
@Transactional(rollbackFor = Exception.class,propagation = Propagation.SUPPORTS)
public void testSupportsNoException() throws RollbackException {
    jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ('"+Global.SUPPORTS_NO_EXCEPTION+"')");
}

复制代码

呼び出し元と呼び出し上記の例では、我々は結果を直接実装を参照してください

2019-10-16 13:50:27.738  INFO 12174 --- [           main] c.e.t.t.TransactionApplication           : 第一种情况 1
2019-10-16 13:50:27.741  INFO 12174 --- [           main] c.e.t.t.TransactionApplication           : 第二种情况 0

复制代码

私たちは、最初のケースで見つかったデータは、説明はトランザクションではありません最初のケースと呼ばれて参照してください。この時点で、私たちは、この文は理解しておくべきでしょう事柄を実行しない方法がない場合は、現在のトランザクションをサポートします

PROPAGATION_MANDATORY

それでもこの2つの例が示します

呼び出し側が業務を持っています 呼び出し側は異常あり 呼び出し側は異常あり
ノー ノー 持っています
持っています 持っています ノー
  • 最初のケース:トランザクションがないので、発信者なので、このプロパティの普及が異常スローする必要があります
  • 後者の場合:呼び出し側のトランザクションおよびトランザクションが同じ呼び出し側であります

次の呼び出し先のコード例

// MANDATORY传播属性-被调用者有异常抛出
@Override
@Transactional(rollbackFor = Exception.class,propagation = Propagation.MANDATORY)
public void testMandatoryHasException() throws RollbackException {
    jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ('"+Global.SUPPORTS_HAS_EXCEPTION+"')");
    throw new RollbackException();
}

// MANDATORY传播属性-被调用者无异常抛出
@Override
@Transactional(rollbackFor = Exception.class,propagation = Propagation.MANDATORY)
public void testMandatoryNoException() throws RollbackException {
    jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ('"+Global.SUPPORTS_NO_EXCEPTION+"')");
}

复制代码

呼び出し元と呼び出し上記の例では、我々は結果を直接実装を参照してください

2019-10-16 13:58:39.178 ERROR 12317 --- [           main] c.e.t.t.TransactionApplication           : org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory'
2019-10-16 13:58:39.276  INFO 12317 --- [           main] c.e.t.t.TransactionApplication           : 第一种情况 0
2019-10-16 13:58:39.281  INFO 12317 --- [           main] c.e.t.t.TransactionApplication           : 第二种情况 0

复制代码

私たちは同じことを見つけて、我々は、我々は考え、この文を理解しておく必要があり、呼び出し先が彼らの新しい情勢ではないことを示す、推測現在のトランザクションが例外をスローしない場合は、現在のトランザクションをサポートします

PROPAGATION_REQUIRES_NEW

伝播特性の下で、関係なく、呼び出し元がトランザクションがあるかどうかの、呼び出し元は新しいトランザクションを作成します。

呼び出し側が業務を持っています 呼び出し側は異常あり 呼び出し側は異常あり
ノー ノー 持っています
持っています 持っています ノー
  • 最初のケース:呼び出し元がないトランザクションは、呼び出し側がそのデータを見つけ、新しいトランザクションを作成します。
  • 後者の場合:呼び出し側のトランザクションがあり、トランザクションが新しい発信者を作成するので、呼び出し側は例外呼び出し側には影響を与えないので、データを見つけることができます

次は、コードをデモ。

呼び出し先

// REQUIRES_NEW传播属性-被调用者有异常抛出
@Override
@Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
public void testRequiresNewHasException() throws RollbackException {
    jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ('"+Global.REQUIRES_NEW_HAS_EXCEPTION+"')");
    throw new RollbackException();
}

// REQUIRES_NEW传播属性-被调用者无异常抛出
@Override
@Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
public void testRequiresNewNoException() throws RollbackException {
    jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ('"+Global.REQUIRES_NEW_NO_EXCEPTION+"')");
}

复制代码

上記の例と同じ呼び出し側は、我々は直接の実装を見て

2019-10-16 16:29:20.296  INFO 15553 --- [           main] c.e.t.t.TransactionApplication           : 第一种情况 0
2019-10-16 16:29:20.298  INFO 15553 --- [           main] c.e.t.t.TransactionApplication           : 第二种情况 1

复制代码

私たちは、そのトランザクションと呼び出し元の呼び出し元のトランザクションは完全に無関係示し、私たちの推論が同じである見つけます。この時点で、私達はちょうどこの文を理解しておく必要がありかかわらず、現在のトランザクションがあるかどうかの、新しいトランザクションを開始します

PROPAGATION_NOT_SUPPORTED

呼び出し元がトランザクションを持っているかどうか、呼び出し元はトランザクションの方法で実行されていません

また、この2つの例

呼び出し側が業務を持っています 呼び出し側は異常あり 呼び出し側は異常あり
ノー ノー 持っています
持っています 持っています ノー
  • 最初の場合:発信者が、対応するデータが例外をスローした後に見つけることができ、取引はできません
  • 後者の場合は:,呼び出し側は、呼び出し元の環境事務の不存在下で実行されるトランザクションの状況を持っているので、我々はまだデータに記載されています

そして、私たちの推測を検証

// NOT_SUPPORTED传播属性-被调用者有异常抛出
@Override
@Transactional(rollbackFor = Exception.class,propagation = Propagation.NOT_SUPPORTED)
public void testNotSupportHasException() throws RollbackException {
    jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ('"+Global.NOT_SUPPORTS_HAS_EXCEPTION+"')");
    throw new RollbackException();
}

// NOT_SUPPORTED传播属性-被调用者无异常抛出
@Override
@Transactional(rollbackFor = Exception.class,propagation = Propagation.NOT_SUPPORTED)
public void testNotSupportNoException() throws RollbackException {
    jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ('"+Global.NOT_SUPPORTS_NO_EXCEPTION+"')");
}

复制代码

そして、結果を表示

2019-10-16 16:38:35.065  INFO 15739 --- [           main] c.e.t.t.TransactionApplication           : 第一种情况 1
2019-10-16 16:38:35.067  INFO 15739 --- [           main] c.e.t.t.TransactionApplication           : 第二种情况 1

复制代码

私たちは、デモの影響によると、この文を理解することができるはず、データで見つかった最後の2例で見ることができ、それは現在のトランザクションが存在する場合、この保留中のトランザクションは、トランザクション・モードで実行されません、トランザクションをサポートしていません

PROPAGATION_NEVER

呼び出し元のトランザクションがあり、呼び出し側は例外がスローされます

呼び出し側が業務を持っています 呼び出し側は異常あり 呼び出し側は異常あり
ノー ノー 持っています
持っています 持っています ノー

これは実証することはありませんが、私たちは最初のケースでは、我々はデータで見つかっされることが可能であることを理解するであろう、ここで表示されるはずと信じています。取引に呼び出し側なぜなら後者の場合、それは例外がスローされます。

PROPAGATION_NESTED

伝播特性の下では、呼び出し側のトランザクションは、トランザクションの発信者のサブセットです。

私たちは、の焦点について話NESTED伝播特性の特性

呼び出し側が業務を持っています 説明
持っています 呼び出し側は、新たなビジネスを開始され、このトランザクションは、関係をネストされたトランザクションの発信者であります
ノー 呼び出し側は、新たな自分の業務を開始します

ネストされたトランザクションとの関係については、私たちが使用することができますどのような次の3つの例を示しています。

呼び出し側が業務を持っています 呼び出し側は異常あり 呼び出し側は異常あり
ノー ノー 持っています
持っています 持っています ノー
持っています ノー 持っています
  • 最初のケース:あなたがいないトランザクションた場合に、発信者、データを見つけることができない場合は、呼び出し側が新しいトランザクションを開始します
  • 第二种情况:如果查不到数据,说明外层事务能够影响内层事务
  • 第三种情况:如果查到数据,说明内层事务不影响外层事务

接下来我们编写具体的代码

// NESTED传播属性-回滚事务
@Override
@Transactional(rollbackFor = Exception.class,propagation = Propagation.NESTED)
public void testNestedHasException() throws RollbackException {
    jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ('"+Global.NESTED_HAS_EXCEPTION+"')");
   // TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    throw new RollbackException();
}

// NESTED传播属性-不回滚事务
@Override
@Transactional(rollbackFor = Exception.class,propagation = Propagation.NESTED)
public void testNestedNoException() throws RollbackException {
    jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ('"+Global.NESTED_NO_EXCEPTION+"')");
}

复制代码

然后接下来的调用者也会有点区别

@Override
@Transactional()
public void hasTransactionalNoException() throws RollbackException {
    // NESTED传播属性 - 调用者有事务,不抛异常  被调用者有异常
    jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ('"+Global.NESTED_HAS_EXCEPTION_TWO+"')");
    fooService.testNestedHasException();
}
复制代码

然后执行效果

2019-10-16 18:01:06.387  INFO 17172 --- [           main] c.e.t.t.TransactionApplication           : 第一种情况 0
2019-10-16 18:01:06.389  INFO 17172 --- [           main] c.e.t.t.TransactionApplication           : 第二种情况 0
2019-10-16 18:01:06.390  INFO 17172 --- [           main] c.e.t.t.TransactionApplication           : 第三种情况 1

复制代码

可以看出来嵌套事务的本质就是外层会影响内层,内层不影响外层。而REQUIRES_NEW则是互不影响

总结

到现在我们已经全部分析完了七种传播属性,从写这篇文章开始到结束其中也碰到过一些坑,有些是不自己实践一遍是根本不知道的,所以我还是建议读者看完这篇文章以后自己进行实践,演示各种情况,只有这样才能够烂熟于心。

本文代码地址

おすすめ

転載: juejin.im/post/5da6eee2f265da5bb977d65c