この記事の主な研究は、春のトランザクションの伝播とその実装原則であり、次のように紹介されます。
Springは現在、Java開発の事実上の基準です。その利便性、完全な機能、使いやすいおかげで。開発プロセス中、DBの操作は非常に一般的な操作であり、DBに関してはトランザクションが含まれます。トランザクションの通常の開発プロセス中に、たとえそれが気づかなくても、プログラムの通常の実行に副作用はありません。ただし、例外が発生し、トランザクションが適切に処理されない場合、予期しない結果が発生する可能性があります。 Springは、トランザクション、特に宣言的トランザクションの出現の観点からさまざまな操作をカプセル化し、開発をより快適にしています。 Springはトランザクションを拡張し、複数の伝播属性の定義をサポートします。これもこの記事の焦点です。
厳密に言えば、トランザクションは複数の操作の略語です。これらの操作は有効になるか、どれも有効になりません(実行されないことに相当します)。一般的な操作プロセスは次のように簡素化されます。
try {connection conn = getConnection(); //いくつかのデータベース操作を実行} catch(例外e){conn.rollback();}最後に{conn.close();}上記のコードからいくつかの問題を見ることができます。
Springは宣言的なトランザクションを提供するため、基礎となる層の特定の実装に注意を払う必要はなく、基礎となるレイヤーの多くの異なる実装の詳細をブロックします。複数の複雑なビジネスによる取引の微細な制御をサポートするために、Springは取引の伝播属性を提供し、宣言的トランザクションと組み合わせて、主要なトランザクションツールになりました。
TransactionDefinitionクラスでは、Springは6つの伝播特性を提供します。これは簡単な例で説明されています。
温かいリマインダー:現在のトランザクションに参加する以下は、下部の同じ接続の使用を指しますが、トランザクション状態オブジェクトは再現でき、影響しません。この記事は、現在1つのトランザクションしかないことを述べています。つまり、基礎となる接続が共有されており、作成されたトランザクション状態オブジェクト(TransactionStatus)の数を気にしません。
説明:トランザクションが既に存在する場合は、トランザクションに参加します。トランザクションがない場合は、トランザクションを作成します。これは、デフォルトの伝播属性値です。
小さな例を見てみましょう。コードは次のとおりです。
@transactionalpublic void service(){servicea(); serviceb();}@transactionalservicea();@transactionalserviceb();ServiceaとServiceBは両方ともトランザクションを宣言します。デフォルトでは、propagation = propagation_required。サービスコールプロセス全体で、共有トランザクションは1つだけです。例外が発生すると、すべての操作がロールバックされます。
説明:トランザクションが既に存在する場合は、トランザクションに参加します。そうしないと、いわゆる空のトランザクションが作成されます(トランザクションの実行はないと見なすことができます)。
小さな例を見てみましょう。コードは次のとおりです。
public void service(){servicea(); new runtimeexception();}@transactional(propagation = propagation.supports)servicea();現在、Serviceaが実行されているときにトランザクションはないため、サービスに投げ込まれた例外はServiceaをロールバックしません。
別の小さな例を見てみましょう。コードは次のとおりです。
public void service(){servicea();}@transactional(propagation = propagation.supports)servicea(){do sql 1 1/0; sql 2}Serviceaには実行時にトランザクションがないため、この時点で、基礎となるデータソースdefaultAutoCommit = trueの場合、SQL1は効果的です。 defaultAutoCommit = falseの場合、SQL1は無効です。サービスに@Transactionalタグがある場合、Serviceaはサービストランザクションを共有します(DefaultAutoCommitに依存しなくなりました)。この時点で、Serviceaはすべて巻き戻されています。
説明:トランザクションが現在存在する必要があります。そうしないと、例外がスローされます。
小さな例を見てみましょう。コードは次のとおりです。
public void service(){serviceb(); servicea();} serviceb(){do sql} @transactional(propagation = propagation.mandatory)servicea(){do sql}この場合、サービスの実行は例外をスローします。 defaultAutoCommit = trueの場合、ServiceBはロールバックされません。 defaultAutoCommit = falseの場合、ServiceBの実行は無効になります。
注:トランザクションが現在存在する場合、最初に現在のトランザクション関連コンテンツをエンティティにカプセル化し、次に新しいトランザクションを再現し、このエンティティをパラメーターとして受け入れ、トランザクションリカバリに使用します。より鈍い声明は、現在のトランザクションを一時停止し(トランザクションは必要ありません)、新しいトランザクションを作成することです。この場合、2つのトランザクション間に依存関係はなく、新しいトランザクションをロールバックできますが、外部トランザクションは実行され続けています。
小さな例を見てみましょう。コードは次のとおりです。
@transactionalpublic void service(){serviceb(); try {servicea(); } catch(exception e){}} serviceb(){do sql} @transactional(propagation = propagation.requires_new)servicea(){do sql 1 1/0; sql 2}Serviceaはrequires_newを使用するため、サービスインターフェイスを呼び出すと、新しいトランザクションが作成されます。ただし、Serviceaはランタイム例外をスローするため、Serviceaはロールバックされます。サービス方法では、例外がキャッチされるため、ServiceBは正常に提出されます。 Try ... Catch Code in Serviceが必要であることに注意してください。そうしないと、サービスが例外をスローし、ServiceBがロールバックされます。
注:トランザクションが現在存在する場合、現在のトランザクションを一時停止し、新しいメソッドがトランザクションのない環境およびスプリングトランザクションのない環境で実行される場合、SQLのコミットはDefaultAutoCommitプロパティ値に完全に依存します。
小さな例を見てみましょう。コードは次のとおりです。
@transactionalpublic void service(){serviceb(); servicea();} serviceb(){do sql} @transactional(propagation = propagation.not_supported)servicea(){do sql 1 1/0; sql 2}サービスメソッドが呼び出されると、ServiceAメソッドの1/0コードが実行されると、例外がスローされます。 Serviceaはトランザクションのない環境にあるため、SQL1が有効かどうかはDefaultAutoCommitの値に依存します。 defaultAutoCommit = trueの場合、SQL1は効果的ですが、サービスが例外をスローするため、ServiceBはロールバックされます。
説明:トランザクションが現在存在する場合、例外がスローされます。そうしないと、コードはトランザクションレス環境で実行されます。
小さな例を見てみましょう。コードは次のとおりです。
public void service(){serviceb(); servicea();} serviceb(){do sql} @transactional(propagation = propagation.never)servicea(){do sql 1 1/0; sql 2}上記の例がサービスを呼び出した後、defaultAutoCommit = trueの場合、ServiceAのServiceBメソッドとSQL1が有効になります。
注:トランザクションが現在存在する場合は、SavePointテクノロジーを使用して現在のトランザクション状態を保存し、その後、基礎となるレイヤーが接続を共有します。ネストされた内部でエラーが発生すると、セーブポイント状態自体にロールバックされます。例外が外部にキャッチされている限り、埋め込まれたビジネスに邪魔されることなく、外部トランザクションをコミットし続けることができます。ただし、外部トランザクションによって例外がスローされると、大規模なトランザクション全体がロールバックされます。
注:Spring Configuration Transaction Managerは、以下に示すように、NestedTransactionAllowed = trueを積極的に指定する必要があります。
<bean id = "dataTransactionmanager"> <プロパティ名= "dataSource" ref = "datadatasource" /> <プロパティ名= "nestedtransactionalowed" value = "true" /> < /bean>
小さな例を参照してください。コードは次のとおりです。
@transactionalpublic void service(){servicea(); try {serviceb(); } catch(Exception e){}} servicea(){do sql} @transactional(propagation = propagation.nested)serviceb(){do sql1 1/0; sql2}ServiceBは組み込みサービスであり、ランタイムの例外が内部にスローされるため、ServiceBはロールバックされます。サービスが例外を獲得したため、Serviceaはそれを正常に送信できます。
別の例を見てみましょう。コードは次のとおりです。
@transactionalpublic void service(){servicea(); serviceb(); 1/0;}@transactional(propagation = propagation.nested)servicea(){do sql} serviceb(){do sql}サービスが例外をスローするため、サービス方法全体がロールバックされます。 (これは、propagation_requires_newとは異なります。ネストされたモードの下に組み込まれたサービスは、外部トランザクションからの例外によって巻き戻されます。)
上記の例は、春のトランザクションによって提供されるいくつかの伝播属性を示しています。これは、ビジネスによって決定できるさまざまなビジネスニーズを満たすために使用されます。次に、春の最も重要な技術的依存関係がこれらの伝播属性を実装するものを見てみましょう。このセクションには、それぞれ簡単な説明について、propagation_requires_newとpropagation.nestedをリストします。
次のコード呼び出し:
@transactionalpublic void service(){serviceb(); try {servicea(); } catch(Exception e){}}@transactional(propagation = propagation.requires_new)servicea(){do sql 1 1/0; do sql 2} serviceb(){do sql}実行回路図は次のとおりです。
a。トランザクションステートオブジェクトを作成し、新しい接続を取得し、オートコンミットをリセットし、接続のその他のプロパティを取得し、タイムアウトします
b。接続をthreadlocal変数にバインドします
c。現在のトランザクションが保留され、現在のトランザクション状態オブジェクト、接続、その他の情報を懸濁液オブジェクトにカプセル化します。
d。新しいトランザクション状態オブジェクトを作成し、新しい接続を再獲得し、オートコンミット、フェッチサイズ、タイムアウト、および新しい接続のその他のプロパティをリセットします。同時に、トランザクションリカバリのためにSuspedResourcesオブジェクトを保存し、新しい接続をthreadlocal変数に結合します(上書き操作)
e。例外をキャッチし、threadlocalの接続をロールバックし、接続パラメーターを復元し、接続を閉じ、suspedendedResourcesを復元します
f。 ThreadLocal変数の接続を送信し(ServiceBが送信される原因)、接続パラメーターを復元し、接続を閉じて、データソースへの接続を返します
したがって、プログラムの実行の結果、Serviceaがロールバックされ、ServiceBが正常に提出されます。
次のコード呼び出し:
@transactionalpublic void service(){servicea(); try {serviceb(); } catch(Exception e){}} servicea(){do sql} @transactional(propagation = propagation.nested)serviceb(){do sql1 1/0; sql2}実行回路図は次のとおりです。
a。トランザクションステートオブジェクトを作成し、新しい接続を取得し、オートコンミットをリセットし、接続のその他のプロパティを取得し、タイムアウトします
b。接続をthreadlocal変数にバインドします
c。現在のトランザクション状態オブジェクトの使用をマークし、threadlocal接続オブジェクトを取得し、現在の接続の保存ポイントを保存し、例外回復に使用されます。現時点では、Serviceaが実行された後のステータスです
d。例外をキャッチし、トランザクションロールバックにCのSavePointを使用します。つまり、Serviceaを実行した後、州を州にロールバックします。 ServiceBメソッドのすべての実行は有効になりません
e。接続オブジェクトをthreadlocalで取得し、トランザクションを送信し、接続プロパティを復元し、接続を閉じます
基礎となるデータソースに基づいて、SpringはThreadlocal、SavePoint、およびその他の技術ポイントを使用して、さまざまな複雑なサービスの実装を容易にするさまざまなトランザクション伝播属性を実現します。伝播属性の原則を理解することによってのみ、春のトランザクションをより適切に制御できます。春のロールバックトランザクションは、例外のキャプチャに依存しています。デフォルトでは、runtimeexceptionとエラーがスローされている場合にのみ、トランザクションがロールバックされます。もちろん、構成できます。詳細については、@Transactional Annotationを確認できます。
Springの宣言的取引は、私たちに非常に便利になります。この武器をうまく利用するためには、根本的な原則を理解する必要があります。この記事は、春取引の氷山の一角にすぎません。読者はこれに基づいて詳細に探索できます。
上記は、春のトランザクション伝播とその実装原則に関するこの記事のすべての内容です。私はそれが誰にでも役立つことを願っています。興味のある友人は、このサイトの他の関連トピックを引き続き参照できます。欠点がある場合は、それを指摘するためにメッセージを残してください。このサイトへのご支援をありがとうございました!