6

Grails アプリでは、サービス メソッドのデフォルトの動作はトランザクションであり、未チェックの例外がスローされた場合、トランザクションは自動的にロールバックされます。ただし、Groovy では、チェック済み例外の処理 (または再スロー) が強制されないため、サービス メソッドがチェック済み例外をスローすると、トランザクションがロールバックされないというリスクがあります。このため、すべての Grails サービス クラスに注釈を付けることが推奨されるようです。

@Transactional(rollbackFor = Throwable.class) 
class MyService {

    void writeSomething() {
    }
}

に他のメソッドがありMyService、そのうちの 1 つは DB を読み取るだけで、もう 1 つは DB に触れないとします。次の注釈は正しいですか?

@Transactional(readOnly = true)
void readSomething() {}

// Maybe this should be propagation = Propagation.NOT_SUPPORTED instead?
@Transactional(propagation = Propagation.SUPPORTS)
void dontReadOrWrite() {}

この質問に答えるには、私の意図が何であるかを知る必要があると思います。

  • いずれかのメソッドから例外がスローされ、進行中のトランザクションがある場合、そのトランザクションはロールバックされます。たとえば、 がwriteSomething()呼び出さdontReadOrWrite()れ、後者から例外がスローされた場合、前者によって開始されたトランザクションはロールバックされます。rollbackForクラスレベルの属性は、明示的にオーバーライドしない限り、個々のメソッドによって継承されると想定しています。
  • 進行中のトランザクションがない場合、次のようなメソッドは開始されません。dontReadOrWrite
  • が呼び出されたときに進行中のトランザクションがない場合readSomething()は、読み取り専用トランザクションが開始されます。読み取り/書き込みトランザクションが進行中の場合、このトランザクションに参加します。
4

2 に答える 2

4

あなたのコードは、それが行く限り正しいです: サービス クラスの個々のメソッドで Spring @Transactional アノテーションを使用して、探している粒度を取得したいのですが、dontReadOrWrite (NOT_SUPPORTED は既存のトランザクションを一時停止します。これは、説明した内容に基づいて何も購入せず、ソフトウェアがサイクルを費やす必要があるため、利益がなければ痛みがあります)、デフォルトの伝播動作が必要なのは正しいです (必須) ) readSomething の場合。

ただし、Spring のトランザクション動作で留意すべき重要な点は、適切なトランザクションのセットアップを行い、メソッドを呼び出し、制御が戻ったときに適切なトランザクションのティアダウンを行うプロキシでクラスをラップすることにより、Spring がトランザクション管理を実装することです。そして (重要なことに)、このトランザクション管理コードは、最初の箇条書きのように writeSomething() が直接 dontReadOrWrite() を呼び出す場合には発生しない、プロキシでメソッドを呼び出した場合にのみ呼び出されます。

別のメソッドによって呼び出されるメソッドで異なるトランザクション動作が必要な場合、Spring の @Transactional アノテーションをトランザクション管理に使用し続けたい場合、私が知っている 2 つの選択肢があります。

  1. 他のメソッドから呼び出されているメソッドを別のサービス クラスに移動します。このサービス クラスは、Spring プロキシを介して元のサービス クラスからアクセスされます。
  2. メソッドはそのままにしておきます。サービス クラスのメンバー変数をサービス クラスのインターフェイスと同じ型になるように宣言し、それを @Autowired にします。これにより、サービス クラスの Spring プロキシ オブジェクトへの参照が提供されます。次に、異なるトランザクション動作でメソッドを呼び出したい場合は、直接ではなくそのメンバー変数で実行すると、必要に応じて Spring トランザクション コードが起動します。

アプローチ #1 は、2 つのメソッドが実際には関連していない場合に最適です。これにより、コードを保守することになる人を混乱させることなく問題を解決でき、トランザクション対応メソッドの呼び出しを誤って忘れる方法がないためです。

メソッドがすべて同じサービスにある理由があり、実際にはそれらを分割したくないと仮定すると、通常はアプローチ #2 がより適切なオプションです。しかし、Spring トランザクションのこのしわを理解していないメンテナーにとっては混乱を招くものであり、呼び出す場所ごとにそのように呼び出すことを覚えておく必要があるため、代償が伴います。私は通常、サービス クラスを不自然に分裂させないためにその代価を喜んで支払いますが、いつものように、それはあなたの状況次第です。

于 2013-01-24T13:58:03.033 に答える
1

あなたが探しているのは、より詳細なトランザクション管理であり、 @Transactional アノテーションを使用することは正しい方向だと思います。そうは言っても、探している動作を提供できるGrails Transaction Handling Pluginがあります。サービス メソッドの呼び出しを DomainClass.withTransaction クロージャーでラップし、探している非標準の動作をパラメータ マップとして withTransaction() メソッドに提供する必要があることに注意してください。

注として、バックエンドでは、 @Transactional アノテーションを使用して実行時のトランザクションの動作を変更することにより、上記で説明したこととまったく同じことを行っています。プラグインのドキュメントは優れているため、十分なガイダンスがなくても問題ないと思います。

これがあなたが探しているものであることを願っています。

于 2012-02-20T16:49:16.037 に答える