95

Spring-data、Hibernate、MySQL、JPA プロジェクトに取り組み始めたところです。手動でクエリを作成することを心配する必要がないように、spring-data に切り替えました。

@Transactionalアノテーションなしでクエリも試したので、spring-data を使用している場合は を使用する必要がないことに気付きました。

@Transactional注釈を使用すべき/すべきではない特定の理由はありますか?

作品:

@Transactional
public List listStudentsBySchool(long id) {
    return repository.findByClasses_School_Id(id);
}

また動作します:

public List listStudentsBySchool(long id) {
    return repository.findByClasses_School_Id(id);
}

前もって感謝します!

4

6 に答える 6

4

質問は少し広く、データ アクセス レイヤーの注釈で減らすことはできないと思います。アプリケーションのスタック全体、適用したいトランザクション戦略などを考慮する必要があります。IBM developerworks サイトには、Mark Richards によるこのトピックに関する非常に包括的な一連の記事があります。ここで最初のものを見つけることができます: https://developer.ibm.com/articles/j-ts1/

よろしくお願いします

于 2012-05-06T11:43:26.607 に答える
1

あなたの例では、リポジトリがある@Transactionalかどうかによって異なります。

はいの場合、サービスは(そのままで)あなたのケースでは使用しないでください@Transactional(使用する意味がないため)。@Transactional別のテーブル/リポジトリを処理するサービスにさらにロジックを追加する予定がある場合は、後で追加できます。その場合、それを使用するポイントがあります。

@Transactionalいいえの場合 -たとえば、まだ交換されていないものを読んでいないなど、分離に問題がないことを確認したい場合は、サービスを使用する必要があります。

--

一般的なリポジトリについて話している場合 (crud コレクション インターフェースとして):

  1. 私は言います:いいえ、@Transactionalを使用しないでください

理由:リポジトリがビジネス コンテキストの外にあり、伝播や分離 (ロックのレベル) を認識すべきではないと考えられる場合。どのトランザクション コンテキストに関与する可能性があるかを推測することはできません。

リポジトリは「ビジネスレス」です(そう信じている場合)

たとえば、リポジトリがあるとします。

class MyRepository
   void add(entity) {...}
   void findByName(name) {...}

MyServiceなどのビジネスロジックがあります

 class MyService() {

   @Transactional(propagation=Propagation.REQUIRED, isolation=Isolation.SERIALIZABLE)
   void doIt() {
      var entity = myRepository.findByName("some-name");
      if(record.field.equal("expected")) {
        ... 
        myRepository.add(newEntity)
      }
   }

 }

つまり、この場合:MyServiceリポジトリを何に含めたいかを決定します。

findByName()この場合、propagation="Required" を使用すると、両方のリポジトリ メソッドが確実add()に実行され、単一のトランザクションに関与し、isolation="Serializable" を使用すると、誰もそれを妨害できないようになります。get() & add() が関与するテーブルのロックを保持します。

しかし、他のサービスは MyRepository を別の方法で使用したい場合があり、トランザクションにまったく関与せず、findByName()メソッドを使用し、現時点で見つけられるものを読み取るための制限に関心がないと言います。

  1. リポジトリを常に有効なエンティティ (ダーティ リードなし) などを返すものとして扱う場合 (ユーザーが誤って使用するのを防ぐ)、はいと言います。つまり、リポジトリは分離の問題 (同時実行性とデータの一貫性) に対処する必要があります。たとえば、次のようになります。

(リポジトリ) にadd(newEntity)、同じ名前のエンティティが既に存在することを最初に確認するときに確認する必要があります。存在する場合は、すべて 1 つのロック作業単位に挿入します。(上記のサービスレベルで行ったことと同じですが、この責任をリポジトリに移動しません)

たとえば、「進行中」状態の同じ名前のタスクが 2 つ存在することはありません (ビジネス ルール)。

 class TaskRepository
   @Transactional(propagation=Propagation.REQUIRED, 
   isolation=Isolation.SERIALIZABLE)
   void add(entity) {
      var name = entity.getName()
      var found = this.findFirstByName(name);
      if(found == null || found.getStatus().equal("in-progress")) 
      {
        .. do insert
      }
   }
   @Transactional
   void findFirstByName(name) {...}

2 つ目は、DDD スタイルのリポジトリに似ています。


次の場合は、さらにカバーする必要があると思います。

  class Service {
    @Transactional(isolation=.., propagation=...) // where .. are different from what is defined in taskRepository()
    void doStuff() {
      taskRepository.add(task);
    }
  }
于 2021-11-25T22:24:26.203 に答える
0

@Repository注釈を使用する必要があります

これは@Repository、チェックされていないSQL例外をSpring Excpetionに変換するために使用され、対処する必要がある唯一の例外はDataAccessException

于 2012-05-01T07:39:06.657 に答える