Laravel 查询异常需分类处理:ModelNotFoundException 返回 404,唯一约束冲突(1062)返回 422,QueryException 日志需脱敏,禁用生产环境查询日志,统一错误响应格式。

如果您在 Laravel 应用中执行数据库查询时遭遇异常,例如数据不存在、唯一约束冲突或连接中断,则可能是由于底层 SQL 错误未被恰当捕获与区分所致。以下是针对 Laravel 框架查询异常的多种处理技巧:
一、捕获并区分 ModelNotFoundException
当使用 findOrFail() 或 firstOrFail() 查找模型但记录不存在时,Laravel 会抛出 ModelNotFoundException。该异常应被明确识别,避免误判为系统级错误。
1、在 App\Exceptions\Handler.php 的 render() 方法中添加类型判断。
2、检查 $exception 是否为 Illuminate\Database\Eloquent\ModelNotFoundException 实例。
3、调用 $request->expectsJson() 判断是否为 API 请求,若是则返回 JSON 格式 404 响应。
4、否则返回 resources/views/errors/404.blade.php 视图。
二、处理 MySQL 唯一约束冲突(SQLSTATE 23000)
QueryException 中的 1062 错误码表示重复条目,属于可预期业务异常,不应归类为 500 内部服务器错误,而应转换为用户可理解的提示。
1、在 Handler@render 中判断 $exception instanceof Illuminate\Database\QueryException。
2、调用 $exception->getPrevious()?->getMessage() 获取原始 PDO 报错信息。
3、使用 strpos() 检测消息中是否包含 "Duplicate entry" 或错误码 "1062"。
4、若匹配,返回 422 状态码及 {"message": "该邮箱已被注册"} 类似结构化响应。
三、安全提取 QueryException 底层错误详情用于日志
默认情况下,QueryException 的 getMessage() 仅显示通用约束违规提示,丢失关键字段名与冲突值,导致线上排查困难。需主动展开上层异常获取真实驱动报错。
1、在 Handler@report 方法中增加 $exception instanceof Illuminate\Database\QueryException 判断。
Laravel Cloud(cloud.laravel.com)。此技能用于处理所有 Laravel Cloud 请求,包括搜索和读取数据。只要任务涉及 Laravel Cloud,即使用此技能。
2、调用 $previous = $exception->getPrevious() 获取 PDOException 实例。
3、使用 $previous?->getMessage() 提取完整错误字符串,如 "SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'test@example.com' for key 'users_email_unique'"。
4、过滤掉可能含敏感信息的值:对邮件、手机号、token 等字段值进行 正则脱敏处理(如 test@***.com) 后再写入日志。
四、避免在生产环境暴露 SQL 查询上下文
DB::enableQueryLog() 会记录全部执行语句及绑定参数,在生产环境启用将严重拖慢性能并泄露业务逻辑,必须禁用。
1、确认 config/database.php 中 'sqlite'、'mysql' 等连接配置下无 enable_query_log => true 设置。
2、检查 .env 文件中无 DB_LOG_ENABLED=true 类似自定义开关。
3、在本地调试时,仅在单个测试方法内临时启用,并确保提交前已移除或注释。
4、上线前运行 php artisan config:clear && php artisan cache:clear 清除可能缓存的调试配置。
五、统一拦截验证失败与查询失败的响应格式
API 接口需保证所有错误响应结构一致:固定字段 message、可选 errors 数组、标准 HTTP 状态码。避免部分接口返回 422+errors,另一些返回 500+text。
1、在 Handler@render 中优先判断 $exception instanceof Illuminate\Validation\ValidationException。
2、接着判断 $exception instanceof Illuminate\Database\Eloquent\ModelNotFoundException。
3、再判断 $exception instanceof Illuminate\Database\QueryException 并按错误码分支处理。
4、对所有匹配的异常,统一构造 response()->json([ 'message' => $defaultMessage, 'errors' => $errors ?? [] ], $statusCode)。

















