必须开启pdo异常模式才能捕获数据库错误,否则db::table()->select()等操作失败仅返回false或null;需配置'pdo_attr' => [pdo::attr_errmode => pdo::errmode_exception],并配合$model->geterror()和$model->getdberror()检查模型层错误。

数据库错误在ThinkPHP里默认不会抛出异常,而是静默返回false或空结果——必须主动开启PDO异常模式,否则try-catch根本捕获不到任何东西。
为什么try-catch包住Db::table()->select()却没捕获到错误
ThinkPHP的数据库底层用的是PDO,但默认PDO::ATTR_ERRMODE是PDO::ERRMODE_SILENT,即出错只返回false,不抛异常。这意味着你写再多try-catch也白搭。
- 检查
config/database.php中是否设置了'pdo_attr' => [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION](TP6推荐写法) - 若用原生PDO连接,必须手动调用
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION) - 未开启时,
Db::query('xxx')失败返回false,Db::table()->find()返回null,都不触发catch - 开启后,语法错误、表不存在、字段不存在等都会抛出
PDOException,才能被catch (PDOException $e)捕获
捕获到PDOException后该做什么
直接echo $e->getMessage()或dump()是危险操作——会把数据库地址、用户名甚至SQL语句暴露给前端。生产环境必须过滤敏感信息。
- 永远不要在
catch里直接返回$e->getMessage()或$e->getTraceAsString() - 记录日志可用
think\facade\Log::error('DB error: ' . $e->getMessage()),但注意$e->getMessage()可能含敏感内容,建议只记$e->getCode()和摘要 - API响应应统一返回
return json(['code' => 500, 'msg' => '数据库操作失败'], 500),绝不透出原始异常 - 调试阶段可临时加
if (app()->isDebug()) { $data['debug'] = ['sql' => Db::getLastSql(), 'code' => $e->getCode()]; },上线前删掉
模型操作失败却没异常?重点查$model->getError()和$model->getDbError()
模型层的错误分两类:业务校验失败(如验证不通过)和数据库执行失败。前者不抛异常,后者才可能抛PDOException,但模型封装后常被拦截。
-
$model->save()返回false≠ 抛异常,此时应立刻查$model->getError()(验证/逻辑错误)和$model->getDbError()(数据库底层报错) -
$model->getError()返回字符串,比如"username不能为空";$model->getDbError()返回数组,含errno、error、sqlstate等 - 常见组合:
$model->getError()为空但$model->getDbError()有内容 → 字段映射错误、主键未设、类型不匹配 - 联表查询失败时,
Db::getLastSql()比异常堆栈更直观——复制出来在MySQL客户端直接执行,看是不是语法或权限问题
事务中数据库异常被静默吞掉?必须在发起侧包try-catch
ThinkPHP在事务中执行模型事件(如afterInsert)时,若回调里抛异常,框架会捕获并尝试记录日志,但默认不中断事务也不向上抛——导致你看到数据没写入,却没有任何提示。
- 别在模型事件函数里自己
try-catch打日志,这拦不住框架层的吞异常逻辑 - 真正该加
try-catch的位置,是调用$model->save()或Db::transaction()的地方 - 批量操作必须把整个事务块包起来:
Db::transaction(function () { $a->save(); $b->save(); });外再套try-catch - 如果用了队列或远程调用(如
afterWrite里发HTTP),务必加超时:Http::timeout(3)->post(...),且catch后不要throw新异常,否则仍会回滚事务
最易忽略的一点:数据库错误处理不是只靠try-catch,它依赖三层配合——PDO异常模式开关、模型错误方法检查、全局异常处理器兜底。少一层,就可能让错误消失在黑盒里。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











