web-dev-qa-db-ja.com

@Controllerではなく@Serviceで@Transactionalを使用する理由

@ Transactional@ Serviceまたは@ Controllerを使用

「通常、トランザクションはサービス層に置く必要があります。」

「通常のケースは、サービス層レベルで注釈を付けることです。」

「トランザクションはサービスレイヤーに属していると考えてください。これは、作業単位とユースケースを知っているトランザクションです。単一のトランザクションで連携する必要があるサービスに複数のDAOが注入されている場合、これが正しい答えです。」 [ソース]

@ serviceレイヤーで@transactionalを使用する欠点

たとえば、saveUser()とsaveEmail()の2つのメソッドがある場合(メールをデータベースに保存して後で送信するため-キューのように)、トランザクションで使用するメソッドsaveUserAndSendEmail(User user)をサービスに作成します。 [ソース]

次のように1つのSave Genericメソッドではなく、サービスレイヤーに多くのメソッドを作成することを意味します

_public <T> long save(T entity) throws DataAccessException {
    Session session = sessionFactory.getCurrentSession();
    long getGenVal=(Long) session.save(entity);
    return getGenVal;
}
_

上記の解決策によれば、LOLをフォローするような多くの方法があることを意味します。

public <T> long saveAccount(T entity)....

public <T> long saveWithAuditLog(T entity, K entity1)....

public <T> long saveWithAuditLogAndEntries(T entity, K entity, M entity)....

この状況を克服する

@Controllerで@Transactionalを使用し、Generic Saveメソッドを作成して、この単純なsaveメソッドを使用してすべてのエンティティ/モデルを保存します。いずれかのメソッドが保存に失敗した場合、コントローラーのすべてのトランザクションは正常にロールバックされます。

@ Transactionalが@Controllerで使用されるようにするその他の状況

@Controllerで:

_pt.save(entity1);
pt.save(entity2);
int a = 2/0;
pt.save(entity3);
_

サービスの@Transactionalの場合、最初の2つのエンティティは正常に保存されましたが、3番目はすべてのトランザクションをロールバックしていません

場合、@ Controllerの@Transactionalは、例外が発生したときにすべてのトランザクションをロールバックします

スタックオーバーフローが「コントローラーでトランザクションを実行しないでください。それらをサービスレイヤークラスに配置してください」と尋ねた理由 [ソース]

18
Shahid Ghafoor

あなたはベストプラクティスについて質問しています。@TransactionalはMVCロジックのデータの永続性を認識していないため、ベストプラクティスはサービスレイヤーで@Controllerをマークすることです。
@Serviceは、分析から生成されたユースケースに基づいて構築され、作業の単位について知っており、再利用の観点から考えると実現されます。Webコンテキストからデスクトップコンテキストに切り替えた場合(たとえば、またはその他の視覚的なフロントエンド)@Controllerレイヤーが存在しない場合、すべてがサービスレイヤーにカプセル化されているため、問題はありません。
A @Serviceはコントラクトであり、プレゼンテーションレイヤーの変更で@Serviceコードの書き換えを要求するべきではありません。
しかし、Springはトランザクションの境界をどこに置くかを気にしません。@Controllerを使用できますが、アプリケーションの保守が難しくなる可能性があります。

これが十分に明確であることを願っています。そうでなければ申し訳ありません。英語は私の母国語ではありません。

25

他の(非トランザクション)サービスを使用する上位層サービスを作成しました。そして、上位層のサービスはトランザクションです。

@Service
public class Service1Impl implements Servcie1 {
    public Object method11(){...}
    public Object method12(){...}
}

@Service
public class Service2Impl implements Service2 {
    public method21(){...}
}

public interface Service1 {
    public Object method11();
    public Object method12();
}

public interface Service2 {
    public Object method21();
}

@Transactional
public interface UpperLayerService {}

@Service
public class UpperLayerServiceImpl implements UpperLayerService {
    @Autowired
    private Service2 service2;
    @Autowired
    private Service3 service3;

    public Object doWork() {
        Object o1 = service1.method11();
        Object o2 = service1.method12();
        Object o3 = service2.method21();
        ....
        Object res = null;//...Any code
        return res;
    }
}
1
Yan Khonski

コントローラーはビューレイヤーにしっかりと固定されており、いつでも変更できます。サービスは引き続き作業単位を所有しており、どのビューがアクセスしているかに関係なく、正しく動作するはずです。私の答え ここ はまだ立っています。

1
duffymo