私たちが最初にプログラマーになったとき、システムの設計は MVC (Model-View-Controller) アーキテクチャーに従うべきであるという先人たちからの「教育」を受けました。システム全体を Model (モデル)、View (ビュー)、Controller (コントローラー) の 3 つのレベルに分割し、ユーザー ビューをビジネス処理から分離し、それらをコントローラーを介して接続して優れたパフォーマンスを実現します。ロジックとロジックの組み合わせは、標準的なソフトウェア レイヤード アーキテクチャです。
MVC 階層化アーキテクチャは、アーキテクチャで最も単純な階層化アプローチです。この階層化されたアーキテクチャに従うために、プロジェクトをビルドするときに、コントローラー、サービス、および dao の 3 つのディレクトリを作成することがよくあります。これらは、それぞれプレゼンテーション層、ロジック層、およびデータ アクセス層に対応します。
各レイヤーの役割は次のとおりです。
-
コントローラー層: 主にアクセス制御の転送、さまざまな基本パラメーターのチェック、または単に再利用できないサービスの処理を行います。
-
サービス層:主にビジネスロジックやトランザクションを扱う
-
Dao レイヤー: 基礎となるデータベース MySQL、Oracle などとのデータのやり取りを担当します。
しかし、ビジネス ロジックがますます複雑になり、より多くのコードが記述されるようになると、この単純な 3 層アーキテクチャの問題がますます明白になります。
MVC アーキテクチャの欠点
従来の MVC 階層化には、次の明らかな問題があります。
-
サービス層のコードが肥大化している
-
サービス層は大規模なトランザクションやネストされたトランザクションが発生しやすく、多くの問題が発生し、トラブルシューティングが非常に困難です
-
dao 層はビジネス ロジックと混在しています
-
dao レイヤーの sql ステートメントが複雑で、関連するクエリが多数ある
この問題を解決するために、「Alibaba Java 開発マニュアル」を参考に、Service 層の下に一般的な業務処理層 (Manager 層) を分離します。
このレイヤード アーキテクチャでは、主にマネージャー レイヤーが追加され、サービス レイヤーとの関係は次のとおりです。マネージャー レイヤーはアトミック サービス インターフェースを提供し、サービス レイヤーはビジネス ロジックに基づいてアトミック インターフェースの配置を担当します。
マネージャー層の特徴
Manager 層は、「Alibaba Java 開発マニュアル」で次のように説明されています。
マネージャ層: 一般的なビジネス処理層で、次の特徴があります。
サードパーティのプラットフォームによってカプセル化されたレイヤーの場合、返された結果を前処理して異常な情報を変換し、上位レイヤー インターフェイスを適応させます。
キャッシング ソリューションやミドルウェアの一般的な処理など、サービス層の一般的な機能の沈下。
DAO 層と対話し、複数の DAO の組み合わせを再利用します。
実際の開発では、このように Manager レイヤーを使用できます
-
複雑なビジネスの場合、サービスはマネージャー層にデータを提供し、ビジネスの手配を担当し、トランザクションをマネージャー層にシンクします.マネージャー層は相互呼び出しを許可せず、トランザクションのネストはありません.
-
ビジネスのないSQL言語、またはマネージャー層での一般的なビジネスのdaoレイヤーカプセル化に焦点を当てます。
-
複雑なジョイン クエリを避ける データベースへの負荷は Java よりもはるかに大きいため、SQL は厳密に制御する必要があるため、複雑なクエリなど、マネージャー レイヤーで分割できます。
もちろん、単純なビジネスの場合、マネージャー レイヤーは使用されない場合があります。
マネージャー層のユースケース
ここでは、マネージャー レイヤーの使用シナリオを示す例を示します。
ユーザー情報を取得するためのインターフェースを持つユーザーシステムがあり、それが getUser
論理サービス層のメソッドを呼び出し、getUser
メソッドが User DB
相互に作用してデータを取得するとします。下図の左側の部分。
このとき、製品は、APP にユーザー情報を表示するときに、ユーザーが存在しない場合、そのユーザーに対してユーザーを自動的に作成する必要があるという要件を提示します。同時に、HTML5 ページを作成するには、HTML5 ページは以前のロジックを保持する必要があります。つまり、ユーザーを作成する必要はありません。
このとき、従来の 3 層アーキテクチャでは、ロジック層の境界が不明確になり、プレゼンテーション層にもビジネスロジックの処理を追加することが多いため、プレゼンテーション層もビジネスロジックの一部を担っています。ユーザーとユーザー インターフェイスを作成します。
Manager層を追加した後、Manager層はユーザーを作成してユーザー情報を取得するためのインターフェースを提供し、Service層はこれら2つのインターフェースを組み立てる役割を果たします。このように、もともとプレゼンテーション層に分散していたビジネスロジックがサービス層に統合され、各層の境界が非常に明確になっています。
次に、実際のコードを見て、サービス レイヤーとマネージャー レイヤーを区別する方法を説明しましょう。
@Transactional(rollbackFor = Throwable.class)
public Result<String> upOrDown(Long departmentId, Long swapId) {
// 验证 1
DepartmentEntity departmentEntity = departmentDao.selectById(departmentId);
if (departmentEntity == null) {
return Result.error("部门xxx不存在");
}
// 验证 2
DepartmentEntity swapEntity = departmentDao.selectById(swapId);
if (swapEntity == null) {
return Result.error("部门xxx不存在");
}
// 验证 3
Long count = employeeDao.countByDepartmentId(departmentId);
if (count != null && count <= 0) {
return Result.error("员工不存在");
}
// 操作数据库 4
Long departmentSort = departmentEntity.getSort();
departmentEntity.setSort(swapEntity.getSort());
departmentDao.updateById(departmentEntity);
swapEntity.setSort(departmentSort);
departmentDao.updateById(swapEntity);
return Result.OK("success");
}
上記のコードは、3 層アーキテクチャを採用している場合によく見られますが、何が問題なのですか?
上記のコードは典型的なロング トランザクションの問題 (サードパーティ インターフェイスの呼び出しに似ています) です。最初の 3 つのステップは、接続を使用して操作を検証することですが、メソッドに @Transactional アノテーションがあるため、これら 3 つの検証はすべて使用しています。同じ接続。
複雑なビジネスおよび複雑な検証ロジックの場合、検証プロセス全体が常に接続接続を占有するため、時間がかかる可能性があり、メソッドが終了するまで接続はデータベース接続プールに返されません。
複雑なビジネスの予測不可能な状況に対して、同じ接続を長時間占有することは良くなく、できるだけ占有時間を短縮する必要があります。
説明: @Transactional アノテーションの場合、Spring がこのアノテーションに遭遇すると、自動的にデータベース接続プールから接続を取得し、トランザクションを開始してから、それを ThreadLocal にバインドします.ビジネスが最終操作データベース リンクに入らない場合、そこに接続を取得してトランザクションを開始する必要がある場合は、他の用途のために接続をデータベース接続プールに直接返す必要があります。
したがって、Manager レイヤーを追加した後、次のように記述できます。
DepartmentService.java
public Result<String> upOrDown(Long departmentId, Long swapId) {
// 验证 1
DepartmentEntity departmentEntity = departmentDao.selectById(departmentId);
if (departmentEntity == null) {
return Result.error("部门xxx不存在");
}
// 验证 2
DepartmentEntity swapEntity = departmentDao.selectById(swapId);
if (swapEntity == null) {
return Result.error("部门xxx不存在");
}
// 验证 3
Long count = employeeDao.countByDepartmentId(departmentId);
if (count != null && count > 0) {
return Result.error("员工不存在");
}
// 操作数据库 4
departmentManager.upOrDown(departmentSort,swapEntity);
return Result.OK("success");
}
DepartmentManager.java
@Transactional(rollbackFor = Throwable.class)
public void upOrDown(DepartmentEntity departmentEntity ,DepartmentEntity swapEntity){
Long departmentSort = departmentEntity.getSort();
departmentEntity.setSort(swapEntity.getSort());
departmentDao.updateById(departmentEntity);
swapEntity.setSort(departmentSort);
departmentDao.updateById(swapEntity);
}
データはサービス レイヤーで準備されてからマネージャー レイヤーに渡され、マネージャー レイヤーは@Transactional
データベース操作のためのトランザクション アノテーションを追加します。