Laravel 5.7事务回滚失效问题排查求助
问题原因分析与解决方案
嘿,我来帮你拆解下这个问题——你遇到的“事务没回滚,第一个表仍创建了记录”的情况,核心原因大概率是数据库存储引擎不支持事务,另外代码里的return逻辑也有小问题,咱们详细说:
1. 数据库引擎不支持事务(最可能的元凶)
Laravel的DB::transaction()完全依赖数据库本身的事务支持,而MySQL里的MyISAM引擎是不支持事务的——哪怕你在代码里写了事务包裹,每个SQL操作都会被自动提交,根本没法回滚。
你可以先检查下User_billings和User_journal这两个表的存储引擎:
- 登录数据库执行这条查询:
SHOW CREATE TABLE User_billings; - 如果结果里显示
ENGINE=MyISAM,那就是这个问题没跑了。
解决办法:把表改成支持事务的InnoDB引擎(Laravel默认推荐的引擎):
ALTER TABLE User_billings ENGINE=InnoDB; ALTER TABLE User_journal ENGINE=InnoDB;
2. 代码里return语句的潜在问题
你的事务闭包内部在成功时直接return response()->json(...),虽然这不是你当前回滚失败的直接原因,但这不符合Laravel事务的最佳实践:
- 事务闭包应该专注于数据操作,响应逻辑放在外面更清晰。
- 闭包里提前return会让事务逻辑提前结束,虽然正常流程下会提交,但异常情况下还是会回滚——只是写法不够规范。
给你优化后的代码示例:
try { DB::transaction(function () use($user,$token,$request) { $billing = User_billings::create([ 'users_id' => $user->id, 'agent_id' => null, 'purpose' => 'Some Purpose', 'agent_token_id'=>$token->id, 'amount' => $request->amount, 'payment_method' => 'Agent Token', 'status' => 1 ]); // 修正了字段名,把bill2_id改成bill_id $user_journal = User_journal::create([ 'bill_id' => $billing->id, 'u_id' => $user->id, 'purpose' => 'Topup via Agent Token', 'debit' => $billing->amount, 'invoice_number' => time() ]); if($this->agentTokenBalance($request->token_id) == 0){ $token->update(['status' => 1]); } }); return response()->json(['status'=>true,'message'=>'TopUp was Successful!']); } catch (\Exception $e) { return response()->json(['status'=>false,'message'=>'TopUp failed: '.$e->getMessage()]); }
3. 额外验证:确保异常能被正确捕获
Laravel的create()方法在SQL执行失败时会自动抛出Illuminate\Database\QueryException,这个异常会被DB::transaction()捕获并触发回滚——但前提是你的数据库支持事务。只要引擎换成InnoDB,异常一抛,事务就会回滚所有操作。
总结:先去检查并修改数据库表的存储引擎为InnoDB,这应该就能解决你遇到的部分操作未回滚的问题啦。
内容的提问来源于stack exchange,提问作者MVP
相关产品推荐
相关产品推荐

