console.log 看不到 sql 实际执行内容,因为数据库驱动异步封装、参数未转义、底层协议数据不可见,需在驱动 i/o 前断点(如 pg 的 query、mysql2 的 execute、prisma 的 _executerequest)并配合日志调试。

为什么 console.log 看不到 SQL 实际执行内容
因为大多数 Node.js 数据库驱动(如 pg、mysql2、prisma)的查询逻辑是异步且封装在内部 Promise 链或连接池中,console.log 打在调用处只能看到原始 SQL 字符串或未解析的参数,看不到最终拼接/转义后的语句,也看不到驱动底层实际发给数据库的 wire 协议数据。
真正想定位异常,得在驱动执行网络 I/O 前一刻打断点——比如 pg 的 client.query 内部、mysql2 的 execute 方法入口、或 Prisma Client 的 _executeRequest。
- 对
pg:在node_modules/pg/lib/client.js的query方法第一行设断点,观察text和values参数是否符合预期 - 对
mysql2:断点打在node_modules/mysql2/lib/connection.js的execute或query函数开头 - Prisma 用户别直接进
node_modules/@prisma/client—— 它是生成代码,优先用PRISMA_CLIENT_ENGINE_TYPE=dataproxy+ 启用log: ['query']配合断点看上下文
VSCode 中断点不命中?检查这三个地方
常见原因是源码映射(source map)未生效、异步跳转丢失上下文、或断点落在了被优化/内联的代码里。
- 确认
launch.json中"sourceMaps": true且"outFiles"指向正确的dist/**/*.js(TypeScript 项目) - 如果用
ts-node直接运行,需加--project tsconfig.json --files,否则断点会因类型检查跳过而失效 - 避免在箭头函数单行表达式里设断点(如
users.map(u => u.id)),V8 可能跳过;拆成带花括号的块语句再断
pg 查询超时却没抛错?试试在 Connection.prototype.sync 下断
pg 的默认行为是:当网络卡住或服务器无响应时,query 不会立刻 reject,而是等底层 socket 超时(通常 30s),期间调试器看起来像“卡死”。但真正的阻塞点常在 sync 或 handleReadyForQuery 这类底层方法。
- 在
node_modules/pg/lib/connection.js中搜索sync,在该函数开头加断点,观察this._reader和this._writer是否有 pending 数据 - 配合
netstat -an | grep :5432看连接状态,若显示SYN_SENT或TIME_WAIT异常,说明不是代码问题,是网络或 pgBouncer 配置问题 - 不要依赖
Promise.race包一层setTimeout就以为解决了——它掩盖了真实连接失败原因,调试时反而更难复现
调试 prisma 查询时,error.stack 里没有 SQL?开日志再断
Prisma 默认隐藏原始 SQL,error.stack 只显示模型层错误(如 P2010)。要看到出问题的那条语句,必须让日志和断点协同工作。
- 启动时加环境变量:
PRISMA_LOG_LEVEL=debug PRISMA_CLIENT_ENGINE_TYPE=dataproxy,并配置log: ['query', 'error']到PrismaClient初始化选项 - 在
node_modules/@prisma/client/runtime/library.js中搜索throw new PrismaClientKnownRequestError,在其上方设断点,此时args对象里通常含sql字段 - 注意:生产环境禁用
log: ['query'],但调试阶段它比任何断点都快——先看日志确认 SQL 是否正确,再决定要不要深入源码断点
pg 或 mysql2 的连接配置里加上 connectionTimeoutMillis 和 idleTimeoutMillis 显式值,这样超时表现更确定,断点也更容易复现。











