✅ この回で学べること
- Service層の役割と設計のポイント
- DAOとServiceの責務の分離
- トランザクション管理の実装例
- 例外処理の設計とベストプラクティス
🧩 Service層の役割とは?
Service層は、「ビジネスロジックを統合」するための層です。
主な責務は以下の通り:
役割 | 内容 |
---|---|
複数DAOの統合 | 1つの業務処理に複数テーブルの更新が必要なときにまとめて呼び出す |
トランザクション制御 | 成功時のコミット/失敗時のロールバックなど |
例外管理 | DAO層のSQLExceptionなどをまとめて扱い、アプリ層に適した例外へ変換 |
✅ シンプルな構成図
Controller(Action)
↓ 呼び出し
Service(業務ロジック・トランザクション制御)
↓ 呼び出し
DAO(DBアクセス)
📌 実装例:Service層でのトランザクション管理
UserService.java(複数DAO+トランザクション制御)
public class UserService {
private UserDao userDao;
private UserRoleDao userRoleDao;
private DataSource dataSource;
public UserService(UserDao userDao, UserRoleDao userRoleDao, DataSource dataSource) {
this.userDao = userDao;
this.userRoleDao = userRoleDao;
this.dataSource = dataSource;
}
public void registerUser(User user, String role) throws ServiceException {
Connection conn = null;
try {
conn = dataSource.getConnection();
conn.setAutoCommit(false); // トランザクション開始
userDao.insert(conn, user);
userRoleDao.assignRole(conn, user.getUserId(), role);
conn.commit(); // 成功時コミット
} catch (SQLException e) {
if (conn != null) {
try {
conn.rollback(); // エラー時ロールバック
} catch (SQLException ex) {
// ロールバック失敗ログ
}
}
throw new ServiceException("ユーザー登録失敗", e);
} finally {
if (conn != null) {
try {
conn.setAutoCommit(true); // 元に戻す
conn.close();
} catch (SQLException ex) {
// ログ記録など
}
}
}
}
}
UserDaoImpl.java(Connectionは引数で受け取る)
public class UserDaoImpl implements UserDao {
public void insert(Connection conn, User user) throws SQLException {
String sql = "INSERT INTO users (user_id, username, email) VALUES (?, ?, ?)";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setInt(1, user.getUserId());
stmt.setString(2, user.getUsername());
stmt.setString(3, user.getEmail());
stmt.executeUpdate();
}
}
}
✅ Service層を設けるメリット
-
業務ロジックを集約できる(Actionに書かない)
-
トランザクション開始・終了の制御を一元化できる
-
エラーハンドリング戦略を統一できる(例:ServiceExceptionにラップ)
☑ よくあるパターン
パターン | 使用例 |
---|---|
単一DAO処理 | Service層を設けず、Action → DAO直呼びでもOK |
複数DAO使用 | Service層でまとめて処理・トランザクション制御が必要 |
ロジック分岐あり | DAOの呼び出し順序や分岐ロジックがある場合はService層で制御 |
💡 例外処理設計のTips
-
DAO層ではSQLExceptionなど「技術例外」をスロー
-
Service層では独自例外(例:ServiceException)でラップ
-
Action層ではServiceExceptionをキャッチして画面遷移制御やログ出力
✅ 今回のまとめ
項目 | ポイント |
---|---|
Service層の目的 | DAOの統合呼び出し・トランザクション・例外管理 |
トランザクション制御 | Service層でConnection開始→DAOに渡す方式が王道 |
例外管理 | DAOでSQLException → Service層で独自例外にラップ |
設計方針 | 単純な処理ならDAOだけ。複雑な処理はService層を設ける |
📘 次回予告:「Vol.10.7:Service層×JUnitテストの基本とパターン」を予定しています!