目次
Spring事务的管理操作方法
spring事务不回滚的两个原因
1. Service类内部方法调用
2. try...catch异常
17.5.3 声明式事务的回滚
Spring トランザクション管理操作メソッド
Spring トランザクションがロールバックされない 2 つの理由
1. Service クラスの内部メソッド呼び出し
17.5.3 宣言型トランザクションのロールバック
ホームページ Java &#&チュートリアル Springトランザクション管理操作方法

Springトランザクション管理操作方法

Jun 20, 2017 pm 04:20 PM
spring 事務 声明 質問

質問です。いつものようにサービスに注釈 @Transactional を追加しましたが、データベースのクエリ時に依然としてデータの不一致が見つかるのはなぜですか? トランザクションが機能していないためだと思います。発生した場合は異常です。ロールバックはありません。そこで、関連するコードをテストしたところ、確かにトランザクションがロールバックされていないことが原因でデータの不整合が発生していることがわかりました。学んだ教訓を以下にまとめましょう: @Transactional,为什么查询数据库时还是发现有数据不一致的情况,想想肯定是事务没起作用,出现异常的时候数据没有回滚。于是就对相关代码进行了一番测试,结果发现一下踩进了两个坑,确实是事务未回滚导致的数据不一致。下面总结一下经验教训:

Spring事务的管理操作方法

  • 编程式的事务管理

    • 实际应用中很少使用

    • 通过使用TransactionTemplate 手动管理事务

  • 声明式的事务管理

    • 开发中推荐使用(代码侵入最少)

    • Spring的声明式事务是通过AOP实现的

主要掌握声明式的事务管理。

spring事务不回滚的两个原因

总结一下导致事务不回滚的两个原因,一是Service类内部方法调用,二是try...catch异常。

1. Service类内部方法调用

大概就是 Service 中有一个方法 A,会内部调用方法 B, 方法 A 没有事务管理,方法 B 采用了声明式事务,通过在方法上声明 Transactional 的注解来做事务管理。示例代码如下:

@Servicepublic class RabbitServiceImpl implements RabbitService {

    @Autowiredprivate RabbitDao rabbitDao;
    @Autowiredprivate TortoiseDao tortoiseDao;

    @Overridepublic Rabbit methodA(String name){return methodB(name);
    }

    @Transactional(propagation = Propagation.REQUIRED)public boolean methodB(String name){
        rabbitDao.insertRabbit(name);
        tortoiseDao.insertTortoise(name);return true;
    }

}
ログイン後にコピー

单元测试代码如下:

public class RabbitServiceImplTest {

    @Autowiredprivate RabbitService rabbitService;// 事务未开启    @Testpublic void testA(){
        rabbitService.methodA("rabbit");
    }// 事务开启    @Testpublic void testB(){
        rabbitService.methodB("rabbit");
    }
}
ログイン後にコピー

从上一节中可以看到,声明式事务是通通过AOP动态代理实现的,这样会产生一个代理类来做事务管理,而目标类(service)本身是不能感知代理类的存在的。

对于加了@Transactional注解的方法来说,在调用代理类的方法时,会先通过拦截器TransactionInterceptor开启事务,然后在调用目标类的方法,最后在调用结束后,TransactionInterceptor 会提交或回滚事务,大致流程如下图:

Springトランザクション管理操作方法

总结,在方法 A 中调用方法 B,实际上是通过“this”的引用,也就是直接调用了目标类的方法,而非通过 Spring 上下文获得的代理类,所以事务是不会开启的。

2. try...catch异常

在一段业务逻辑中对数据库异常进行了处理,使用了try...catch子句捕获异常并throw了一个自定义异常,这种情况导致了事务未回滚,示例代码如下:

@Transactional(propagation = Propagation.REQUIRED)public boolean methodB(String name) throws BizException {try {
        rabbitDao.insertRabbit(name);
        tortoiseDao.insertTortoise(name);
    } catch (Exception e) {throw new BizException(ReturnCode.EXCEPTION.code, ReturnCode.EXCEPTION.msg);
    }return true;
}
ログイン後にコピー

BizException的定义如下:

public class BizException extends Exception {// 自定义异常}
ログイン後にコピー

上面代码中的声明式事务在出现异常的时候,事务是不会回滚的。在代码中我虽然捕获了异常,但是同时我也抛出了异常,为什么事务未回滚呢?猜测是异常类型不对,于是开始查询原因,翻看了Spring的官方文档,找到了答案。下面是翻译自Spring官网。

17.5.3 声明式事务的回滚

上一节中介绍了如何设置开启Spring事务,一般在你的应用的Service层代码中设置,这一节将介绍在简单流行的声明式事务中如何控制事务回滚。

在Spring FrameWork 的事务框架中推荐的事务回滚方法是,在当前执行的事务上下文中抛出一个异常。如果异常未被处理,当抛出异常调用堆栈的时候,Spring FrameWork 的事务框架代码将捕获任何未处理的异常,然后并决定是否将此事务标记为回滚。

  • 在默认配置中,Spring FrameWork 的事务框架代码只会将出现runtime, unchecked

    Spring トランザクション管理操作メソッド

プログラムによるトランザクション管理

      開発推奨(コード侵入最小限)
    • Springの宣言型トランザクションはAOPで実装されています

    主に宣言型のトランザクション管理をマスターします。

    Spring トランザクションがロールバックされない 2 つの理由

    トランザクションがロールバックされない 2 つの理由をまとめてみましょう。1 つは Service クラスの内部メソッド呼び出しで、もう 1 つは try...例外をキャッチします。 🎜
    1. Service クラスの内部メソッド呼び出し
    🎜 おそらく Service にはメソッド B を内部で呼び出すメソッド A があり、メソッド A にはトランザクション管理がなく、メソッド B は宣言型トランザクションを使用します。メソッドについて トランザクション管理のためのトランザクション アノテーション。サンプル コードは次のとおりです: 🎜🎜
    <advice>
      <attributes>
      <method></method>
      <method></method>
      </attributes>
    </advice>
    ログイン後にコピー
    ログイン後にコピー
    🎜🎜 単体テスト コードは次のとおりです: 🎜🎜
    @Transactional(rollbackForClassName={"Exception"})
    或者
    @Transactional(rollbackFor={Exception.class})
    ログイン後にコピー
    🎜🎜 前のセクションからわかるように、宣言的トランザクションは AOP 動的プロキシを通じて実装され、これにより、次のプロキシ クラスが生成されます。トランザクション管理 、およびターゲット クラス (サービス) 自体はプロキシ クラスの存在を認識できません。 🎜🎜 @Transactional アノテーションが付けられたメソッドの場合、プロキシ クラスのメソッドを呼び出すと、インターセプター TransactionInterceptor を通じてトランザクションが開始され、呼び出しが完了した後、最後にターゲット クラスのメソッドが呼び出されます。コミットまたはロールバックします トランザクションの一般的なプロセスは次のとおりです: 🎜🎜トランザクション呼び出しの原則」/> 🎜🎜まとめると、メソッドAでメソッドBを呼び出すとき、実際にはthisの参照を介して、つまり、ターゲットクラスのメソッドを直接呼び出します。 Spring コンテキストなので、トランザクションは開始されません。 🎜<h5>2. try...catch 例外</h5>🎜 データベース例外はビジネス ロジックの一部で処理され、try...catch 句を使用して例外をキャプチャし、カスタム例外をスローします。この状況により、トランザクションはロールバックされません。サンプル コードは次のとおりです。 🎜🎜<pre class=<tx:advice id=" txadvice>   <attributes>   <method></method>   <method></method>   </attributes> 🎜🎜 BizException の定義は次のとおりです。 🎜🎜<div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">@Transactional(noRollbackForClassName={"InstrumentNotFoundException"}) 或者 @Transactional(noRollbackFor={InstrumentNotFoundException.class})
    ログイン後にコピー
    ログイン後にコピー
    🎜🎜 上記のコードの宣言型トランザクションは、例外が発生します。コード内で例外をキャッチしましたが、同時に例外もスローしました。なぜトランザクションはロールバックされなかったのですか?例外の種類が間違っているのではないかと思い、その理由を探し始め、Spring の公式ドキュメントを調べて、答えを見つけました。以下はSpring公式サイトより転載です。 🎜
    17.5.3 宣言型トランザクションのロールバック
    🎜 前のセクションでは、Spring トランザクションを設定して有効にする方法を紹介しました。これは通常、アプリケーションのサービス層コードで設定されます。このセクションでは、シンプルで一般的なものを紹介します。宣言的トランザクションでトランザクションのロールバックを制御する方法。 🎜🎜 Spring FrameWork トランザクション フレームワークで推奨されるトランザクション ロールバック方法は、現在実行中のトランザクション コンテキストで例外をスローすることです。例外が処理されない場合、Spring FrameWork のトランザクション フレームワーク コードは、例外がコール スタックにスローされたときに未処理の例外をキャッチし、トランザクションにロールバックのマークを付けるかどうかを決定します。 🎜🎜🎜🎜 デフォルト設定では、Spring FrameWork のトランザクション フレームワーク コードは、runtime, unchecked 例外を持つトランザクションのみをロールバックとしてマークします。つまり、トランザクションでスローされる例外は RuntimeException またはその例外です。サブクラスを作成し、トランザクションがロールバックされるようにします (デフォルトでは、エラーによってもトランザクションがロールバックされます)。デフォルトの構成では、チェックされた例外はすべてトランザクションのロールバックを引き起こしません。 🎜🎜🎜🎜🎜 注: 未チェックの例外には、Error と RuntimeException が含まれます。RuntimeException のすべてのサブクラスもこのカテゴリに属します。もう 1 つのタイプは「例外」にチェックされます。 🎜🎜🎜🎜🎜例外タイプを正確に構成し、チェック例外を含むこの例外タイプのトランザクション ロールバックを指定できます。次の XML コード スニペットは、チェック例外を構成してトランザクション ロールバックを引き起こし、カスタム例外タイプを適用する方法を示しています: 🎜🎜🎜🎜
    <advice>
      <attributes>
      <method></method>
      </attributes>
    </advice>
    ログイン後にコピー
    ログイン後にコピー
    🎜🎜 同じ効果を持つ注釈フォームは次のとおりです: 🎜🎜
    public void resolvePosition() {  try {      // some business logic...
      } catch (NoProductInStockException ex) {      // trigger rollback programmatically      TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
      }
    }
    ログイン後にコピー
    ログイン後にコピー
    🎜
    • 在你遇到异常不想回滚事务的时候,同样的你也可指定不回滚的规则,下面的一个例子告诉你,即使遇到未处理的 InstrumentNotFoundException 异常时,Spring FrameWork 的事务框架同样会提交事务,而不回滚。

    <advice>
      <attributes>
      <method></method>
      <method></method>
      </attributes>
    </advice>
    ログイン後にコピー
    ログイン後にコピー

      与其有同样作用的注解形式如下:   

    @Transactional(noRollbackForClassName={"InstrumentNotFoundException"})
    或者
    @Transactional(noRollbackFor={InstrumentNotFoundException.class})
    ログイン後にコピー
    ログイン後にコピー
    • 还有更灵活的回滚规则配置方法,同时指定什么异常回滚,什么异常不回滚。当Spring FrameWork 的事务框架捕获到一个异常的时候,会去匹配配置的回滚规则来决定是否标记回滚事务,使用匹配度最强的规则结果。因此,下面的配置例子表达的意思是,除了异常 InstrumentNotFoundException 之外的任何异常都会导致事务回滚。

    <advice>
      <attributes>
      <method></method>
      </attributes>
    </advice>
    ログイン後にコピー
    ログイン後にコピー
    • 你也可以通过编程式的方式回滚一个事务,尽管方法非常简单,但是也有非常强的代码侵入性,使你的业务代码和Spring FrameWork 的事务框架代码紧密的绑定在一起,示例代码如下:

    public void resolvePosition() {  try {      // some business logic...
      } catch (NoProductInStockException ex) {      // trigger rollback programmatically      TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
      }
    }
    ログイン後にコピー
    ログイン後にコピー

      如果可能的话,强烈推荐您使用声明式事务方式回滚事务,对于编程式事务,如果你强烈需要它,也是可以使用的,but its usage flies in the face of achieving a clean POJO-based architecture.(没懂...)

    看完官方文档这节内容找到了问题的答案,原来是因为我们自定义的异常不是 RuntimeException。我的解决办法是,在注解@Transactional中添加 rollbackFor={BizException.class}。可能你会问我为什么不将自定义异常修改为继承RuntimeException,因为我需要BizException是一个checked 异常。

    以上がSpringトランザクション管理操作方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    このウェブサイトの声明
    この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

    ホットAIツール

    Undresser.AI Undress

    Undresser.AI Undress

    リアルなヌード写真を作成する AI 搭載アプリ

    AI Clothes Remover

    AI Clothes Remover

    写真から衣服を削除するオンライン AI ツール。

    Undress AI Tool

    Undress AI Tool

    脱衣画像を無料で

    Clothoff.io

    Clothoff.io

    AI衣類リムーバー

    Video Face Swap

    Video Face Swap

    完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

    ホットツール

    メモ帳++7.3.1

    メモ帳++7.3.1

    使いやすく無料のコードエディター

    SublimeText3 中国語版

    SublimeText3 中国語版

    中国語版、とても使いやすい

    ゼンドスタジオ 13.0.1

    ゼンドスタジオ 13.0.1

    強力な PHP 統合開発環境

    ドリームウィーバー CS6

    ドリームウィーバー CS6

    ビジュアル Web 開発ツール

    SublimeText3 Mac版

    SublimeText3 Mac版

    神レベルのコード編集ソフト(SublimeText3)

    Spring Boot と OpenAI の出会いによる新しいプログラミング パラダイム Spring Boot と OpenAI の出会いによる新しいプログラミング パラダイム Feb 01, 2024 pm 09:18 PM

    2023年、AI技術が注目を集め、プログラミング分野を中心にさまざまな業界に大きな影響を与えています。 AI テクノロジーの重要性に対する人々の認識はますます高まっており、Spring コミュニティも例外ではありません。 GenAI (汎用人工知能) テクノロジーの継続的な進歩に伴い、AI 機能を備えたアプリケーションの作成を簡素化することが重要かつ緊急になっています。このような背景から、AI 機能アプリケーションの開発プロセスを簡素化し、シンプルかつ直観的にし、不必要な複雑さを回避することを目的とした「SpringAI」が登場しました。 「SpringAI」により、開発者はAI機能を搭載したアプリケーションをより簡単に構築でき、使いやすく、操作しやすくなります。

    Spring Boot と Spring AI を使用して生成人工知能アプリケーションを構築する Spring Boot と Spring AI を使用して生成人工知能アプリケーションを構築する Apr 28, 2024 am 11:46 AM

    Spring+AI は業界リーダーとして、強力で柔軟な API と高度な機能を通じてさまざまな業界に最先端のソリューションを提供します。このトピックでは、さまざまな分野での Spring+AI の応用例を詳しく掘り下げ、Spring+AI がどのように特定のニーズを満たし、目標を達成し、これらの教訓をより広範囲のアプリケーションに拡張するかを示します。このトピックが Spring+AI の無限の可能性をより深く理解し、活用するきっかけになれば幸いです。 Spring フレームワークはソフトウェア開発の分野で 20 年以上の歴史があり、Spring Boot 1.0 バージョンがリリースされてから 10 年が経過しました。今、その春に異論を唱える人はいない

    Springプログラマティックトランザクションの実装方法は何ですか? Springプログラマティックトランザクションの実装方法は何ですか? Jan 08, 2024 am 10:23 AM

    Spring プログラムによるトランザクションを実装する方法: 1. TransactionTemplate を使用する; 2. TransactionCallback および TransactionCallbackWithoutResult を使用する; 3. Transactional アノテーションを使用する; 4. TransactionTemplate を @Transactional と組み合わせて使用​​する; 5. トランザクション マネージャーをカスタマイズする。

    Spring でトランザクション分離レベルを設定する方法 Spring でトランザクション分離レベルを設定する方法 Jan 26, 2024 pm 05:38 PM

    Spring でトランザクション分離レベルを設定する方法: 1. @Transactional アノテーションを使用します; 2. Spring 構成ファイルに設定します; 3. PlatformTransactionManager を使用します; 4. Java 構成クラスに設定します。詳細な導入方法: 1. @Transactional アノテーションを使用し、トランザクション管理が必要なクラスまたはメソッドに @Transactional アノテーションを追加し、属性に分離レベルを設定します。 2. Spring の設定ファイルなどで

    MySQL トランザクション処理: 自動送信と手動送信の違い MySQL トランザクション処理: 自動送信と手動送信の違い Mar 16, 2024 am 11:33 AM

    MySQL トランザクション処理: 自動送信と手動送信の違い。MySQL データベースでは、トランザクションは一連の SQL ステートメントです。すべての実行が成功するか、すべての実行が失敗するかのいずれかで、データの一貫性と整合性が保証されます。 MySQL では、トランザクションは自動送信と手動送信に分けられ、その違いはトランザクション送信のタイミングとトランザクションの制御範囲にあります。以下では、自動送信と手動送信の違いを詳しく紹介し、具体的なコード例を示して説明します。 1. MySQL が表示されない場合は自動的に送信する

    jQueryがform要素の値を取得できない問題の解決方法 jQueryがform要素の値を取得できない問題の解決方法 Feb 19, 2024 pm 02:01 PM

    jQuery.val() が使用できない問題を解決するには、具体的なコード例が必要です フロントエンド開発者にとって、jQuery の使用は一般的な操作の 1 つです。その中でも、.val() メソッドを使用してフォーム要素の値を取得または設定する操作は、非常に一般的な操作です。ただし、特定のケースでは、.val() メソッドを使用できないという問題が発生する可能性があります。この記事では、いくつかの一般的な状況と解決策を紹介し、具体的なコード例を示します。問題の説明 jQuery を使用してフロントエンド ページを開発する場合、時々次のような問題が発生します。

    PHP PDO チュートリアル: 基本から習得までの上級ガイド PHP PDO チュートリアル: 基本から習得までの上級ガイド Feb 19, 2024 pm 06:30 PM

    1. PDO の概要 PDO は、データベースを操作するためのオブジェクト指向の方法を提供する PHP の拡張ライブラリです。 PDO は、Mysql、postgresql、oracle、SQLServer などのさまざまなデータベースをサポートします。 PDO を使用すると、開発者は統合 API を使用してさまざまなデータベースを操作できるため、さまざまなデータベースを簡単に切り替えることができます。 2. PDO はデータベースに接続します PDO を使用してデータベースに接続するには、まず PDO オブジェクトを作成する必要があります。 PDO オブジェクトのコンストラクターは、データベース タイプ、ホスト名、データベース ユーザー名、およびパスワードの 3 つのパラメーターを受け取ります。たとえば、次のコードは、mysql データベースに接続するオブジェクトを作成します。 $dsn="mysq

    MySQL トランザクションの原則と適用シナリオ MySQL トランザクションの原則と適用シナリオ Mar 02, 2024 am 09:51 AM

    MySQL トランザクションの原理と適用シナリオ データベース システムでは、トランザクションは一連の SQL 操作であり、これらの操作はすべて正常に実行されるか、すべて失敗してロールバックされます。一般的に使用されるリレーショナル データベース管理システムとして、MySQL はトランザクション特性をサポートし、データベース内のデータの一貫性、分離性、耐久性、アトミック性を保証できます。この記事では、MySQL トランザクションの基本原則から始めて、そのアプリケーション シナリオを紹介し、読者の参考となる具体的なコード例を示します。 MySQL トランザクションの原則: My

    See all articles