You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel DDD模式:是否应将Try-Catch移至控制器及事务处理方案

Laravel DDD模式下事务与异常处理的分层设计

现有代码实现

PostController

public function store(StorePostRequest $request): JsonResponse
{
    return $this->postService->store($request);
}

PostService

public function store(StorePostRequest $request): JsonResponse
{
    DB::beginTransaction();

    try {
        $post = new Post();

        $post->uuid = Str::uuid();
        $post->title = $request->input('title');
        $post->description = $request->input('description');
        $post->status_id = $request->input('status_id');
        $post->created_by_user_id = Auth::id();

        $this->postRepository->store($post);

        DB::commit();

        return response()->json(['status' => true, __('service.the_operation_was_successful')]);
    } catch (Exception $exception) {
        DB::rollBack();

        return response()->json(['status' => false, __('service.error_occurred_during_operation')], 500);
    }
}

PostRepository

public function store(Post $post): Post
{
    $post->save();

    return $post;
}

核心疑问

是否应该将try-catch块移至控制器端,以让Service层代码更简洁?如果迁移,该如何处理DB::beginTransaction()事务操作?


解答

1. 应该将异常处理移至控制器端

Service层的核心职责是处理业务逻辑,不应该耦合HTTP响应、异常返回这类Web请求相关逻辑。把try-catch移到控制器后:

  • Service层代码更纯粹,可复用性更强(比如被CLI命令、队列任务调用时,无需适配HTTP响应逻辑);
  • 符合分层设计原则:控制器专注处理HTTP请求与响应,Service专注业务规则,Repository专注数据持久化。

2. 事务操作的优化处理

无需手动管理beginTransaction()、commit()、rollBack(),可以利用Laravel提供的DB::transaction()闭包自动处理事务,同时让异常自然向上抛出给控制器处理。

重构后的代码示例

重构PostService

去掉HTTP响应和异常捕获,专注业务逻辑与事务管理:

public function store(StorePostRequest $request): Post
{
    // 闭包自动管理事务:无异常自动提交,有异常自动回滚
    return DB::transaction(function () use ($request) {
        $post = new Post();
        $post->uuid = Str::uuid();
        $post->title = $request->input('title');
        $post->description = $request->input('description');
        $post->status_id = $request->input('status_id');
        $post->created_by_user_id = Auth::id();

        return $this->postRepository->store($post);
    });
}
重构PostController

负责捕获异常并返回HTTP响应:

public function store(StorePostRequest $request): JsonResponse
{
    try {
        $this->postService->store($request);
        return response()->json(['status' => true, __('service.the_operation_was_successful')]);
    } catch (Exception $exception) {
        return response()->json(['status' => false, __('service.error_occurred_during_operation')], 500);
    }
}

进阶优化:自定义业务异常

如果需要区分业务逻辑错误和系统错误,可以自定义业务异常类(比如PostCreationFailedException),在Service层不符合业务规则时抛出,控制器针对性捕获处理:

// 自定义异常类
class PostCreationFailedException extends \Exception {}

// Service层抛出异常
public function store(StorePostRequest $request): Post
{
    return DB::transaction(function () use ($request) {
        // 新增业务校验逻辑
        if (empty($request->input('title'))) {
            throw new PostCreationFailedException('标题不能为空');
        }

        $post = new Post();
        // ... 赋值逻辑
        return $this->postRepository->store($post);
    });
}

// 控制器捕获不同异常
public function store(StorePostRequest $request): JsonResponse
{
    try {
        $this->postService->store($request);
        return response()->json(['status' => true, __('service.the_operation_was_successful')]);
    } catch (PostCreationFailedException $e) {
        return response()->json(['status' => false, $e->getMessage()], 400);
    } catch (Exception $e) {
        return response()->json(['status' => false, __('service.error_occurred_during_operation')], 500);
    }
}

内容的提问来源于stack exchange,提问作者JFeel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 15:07:15