プログラムによるトランザクション |
Spring は、プログラムによるトランザクションと宣言的なトランザクションの両方をサポートできます。
Springが提供する最も原始的なトランザクション管理メソッドは、TransactionDefinition、PlatformTransactionManager、TransactionStatus のプログラム トランザクションに基づいています。TransactionTemplateのプログラムによるトランザクション管理は、テンプレート メソッド設計パターンを使用して元のトランザクション管理メソッドをカプセル化した
ものです。
なぜプログラムによるトランザクションを使用するのでしょうか?
プログラムによるトランザクションは、トランザクションのコミットまたはロールバックを制御するプログラムを作成することによって、データベース操作で使用されるトランザクション処理方法です。宣言型トランザクションと比較して、プログラムによるトランザクションはトランザクションの開始、コミット、ロールバックなどの操作を手動で指定する必要があり、よりきめ細かい制御機能を備えています。
プログラムによるトランザクションを使用する利点は次のとおりです。
柔軟性:プログラムによるトランザクションは、ビジネス ロジックとデータ操作の複雑さに応じて柔軟に制御および処理でき、データの一貫性と整合性が保証されます。
可読性:プログラムによるトランザクション コードは、トランザクションの境界と実行シーケンスを直接表示できるため、理解とデバッグに便利です。
セキュリティ:プログラムによるトランザクションを使用すると、データベースのデッドロックやデータの競合などの問題を防止し、複数の同時アクセスにおけるデータのセキュリティと信頼性を確保できます。
クロスフレームワークのサポート:プログラムによるトランザクションは、特定のフレームワークやコンテナーに依存せずにフレームワーク間で使用できるため、開発者は開発と展開に独自のツールを自由に選択できます。
増分変更:プログラムによるトランザクションを使用すると、各トランザクションのサイズと範囲を制御できるため、大規模システムの要件が頻繁に変更される場合に便利で、システムの一部の機能を意図せずに追加または変更する方が便利です。システム全体に影響を与えます。
もちろん、プログラムによるトランザクションの利用には、コードが長い、保守性が悪いなどのデメリットもありますので、利用する際にはメリットとデメリットを比較検討し、ビジネスニーズに応じて最適なトランザクション処理方法を選択する必要があります。
個人は、たとえば次のようなビジネス ニーズのためにこれを選択します。
// 原代码
@Transactional(rollbackFor = Exception.class)
public Boolean alterOperation(Object obj){
// 查询操作1
object1 = service.select();
// 数据处理
.......
// 查询操作2
object2 = service.select2();
// 查询操作3
object3 = service.select3();
.....
// 此处省略查询操作与逻辑......
// 最后增删改操作.....
boolean rs = update();
}
上記のメソッドはアノテーションを使用してトランザクションを開いており、比較的長いトランザクションであることがわかります。メソッド全体でクエリなどの論理操作が多数実行されます。クエリが複雑な場合、クエリ時間が長くなり、トランザクションへの影響がさらに悪化します。システム リソースとパフォーマンス。したがって、他のクエリがリソースとロックをより速く取得できるように、ここでトランザクションの実行時間を短縮してみてください。
今できることは次のとおりです。
長いトランザクションを分割する: 長いプロセスをできる限り複数の短いトランザクションに分割して、各トランザクションが必要なデータとロジックのみに焦点を当て、トランザクション内の不要な他のリソースがロックされるのを避ける必要があります。
トランザクション分離レベルを下げる: 分離レベルを最高レベル (Serializable など) から低いレベル (Read Committed など) に下げると、ロックの数と範囲が減り、同時実行パフォーマンスが向上しますが、データの整合性の問題が発生する可能性もあります。意思決定を行うにはリスクを評価する必要がある。
オプティミスティック ロックを使用する: レコードを更新するときに、オプティミスティック ロック テクノロジを使用できます。つまり、最初にレコードを読み取り、そのバージョン番号やタイムスタンプなどの情報を変数に保存し、変更時にレコードが他のトランザクションによって更新されたかどうかを確認します。そうでない場合は、更新操作を実行します。この方法により、悲観的ロックを使用して多くのリソースを占有することを回避できます。
データベース アーキテクチャを合理的に設計する: テーブル設計とインデックスを合理的に設計すると、ロックの粒度を下げることができ、パーティション テーブルやシャーディングを有効にすると、複数のノードにまたがってデータがクエリされるのを防ぐこともできます。
以下では、プログラムによるトランザクションを使用して長いトランザクションを分割します。
基本的な使用法: トランザクションの粒度を減らし、クエリが長時間ブロックされるのを防ぎます。
# 引用注入 事务模板
@Autowired
private TransactionTemplate transactionTemplate;
# 在需要添加事务方法里编写代码
public Boolean test(){
// 各种查询代码
// 开启事务
Boolean rs = transactionTemplate.execute(transactionStatus -> {
return Boolean.TRUE; 或者 return Boolean.FALSE;
}
}
したがって、TransactionTemplate.execute( ... ) を使用してトランザクション管理を実行する場合、受信パラメータには 2 つのオプションがあります:
1. TransactionCallback
2.
TransactionCallbackWithoutResult の違いは、名前から明らかです。1 つは戻り値を持ち、もう 1 つは戻り値を持ちます。もう 1 つは戻り値なしです。この選択は、読み取りを行うか書き込みを行うかによって異なります。
例:
(TransactionCallback) を使用してトランザクション管理を実行します。両方とも戻り値を使用します。
public Object getObject(String str) {
/*
* 执行带有返回值<Object>的事务管理
*/
transactionTemplate.execute(new TransactionCallback<Object>() {
@Override
public Object doInTransaction(TransactionStatus transactionStatus) {
try {
...
//....... 业务代码
return new Object();
} catch (Exception e) {
//回滚
transactionStatus.setRollbackOnly();
return null;
}
}
});
}
(TransactionCallbackWithoutResult) でトランザクション管理を実行します。戻り値はどちらもありません:
public void update(String str) {
/*
* 执行无返回值的事务管理
*/
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
try {
// .... 业务代码
} catch (Exception e){
//回滚
transactionStatus.setRollbackOnly();
}
}
});
}