应将事务逻辑从Laravel控制器解耦:一、用DB::transaction()闭包封装;二、提取为控制器私有方法;三、创建Service类封装;四、结合Repository模式协调多仓储;五、用Artisan命令处理后台批量事务。

如果您在Laravel控制器中直接编写数据库操作而未统一管理事务边界,可能导致数据不一致或异常后无法回滚。以下是将事务逻辑从控制器中解耦并封装的多种实现方式:
一、使用DB::transaction()匿名函数封装
该方式将整个业务逻辑包裹在闭包中,由Laravel自动处理提交与回滚,适用于逻辑较短且不需复用的场景。
1、在控制器方法中调用DB::transaction(),传入包含多个Eloquent操作的闭包。
2、在闭包内依次执行模型创建、更新、删除等操作。
3、若闭包内抛出Exception或未正常结束,事务自动回滚;否则自动提交。
4、将可能触发异常的业务校验(如库存不足)置于闭包内部,确保其纳入事务保护范围。
二、提取为私有方法并在控制器中调用
将事务体抽离为控制器内的私有方法,保持控制器可读性,同时复用同一事务上下文。
1、在控制器中定义private function handleOrderTransaction(array $data) { ... }。
2、该方法内部使用DB::transaction()包裹具体模型操作。
3、在主控制器动作中调用此私有方法,并捕获其可能抛出的QueryException。
4、根据返回结果或异常类型组织响应内容,注意不可在私有方法外执行任何影响事务状态的DB操作。
三、创建独立的Service类封装事务
遵循MVC分层原则,将事务逻辑下沉至应用服务层,控制器仅负责接收请求与返回响应。
1、运行php artisan make:class Services/OrderService创建服务类。
2、在OrderService中定义public function placeOrder(array $data)方法,并在其内部使用DB::transaction()。
3、控制器中通过app(OrderService::class)或构造注入获取实例并调用该方法。
4、所有Eloquent模型操作必须在Service方法内部完成,控制器不得直接调用save()或delete()。
四、利用Repository模式配合事务管理
通过仓储接口与实现分离数据访问细节,在事务中协调多个仓储操作,增强可测试性与可替换性。
1、定义OrderRepositoryInterface和EloquentOrderRepository实现类。
2、在Service类中依赖注入多个Repository实例(如OrderRepository、InventoryRepository)。
3、在DB::transaction()闭包中依次调用各Repository的方法执行写入。
4、所有Repository方法应只做单表CRUD,跨表一致性由Service层的事务统一保障。
五、使用自定义Artisan命令封装后台事务逻辑
针对非HTTP请求触发的长周期或批量事务操作(如定时同步订单),将事务封装于命令类中执行。
1、运行php artisan make:command ProcessPendingOrders生成命令类。
2、在handle()方法中启动DB::transaction(),并调用相关模型逻辑。
3、通过schedule()方法注册到Kernel中实现定时运行,或手动执行php artisan process:pending-orders。
4、命令类中禁止访问Request、Session等HTTP专属对象,确保与Web层完全隔离。

















