prisma不支持任意原生sql执行,$queryraw仅接受prisma.sql模板并强制参数化,$queryrawunsafe仅限完全可控无外部输入场景;node.js 20需升级pg驱动≥v8.11.0及prisma client≥v5.14.0。

Prisma 本身不支持直接执行任意原生 SQL(如 SELECT * FROM users WHERE ...),这是设计上的主动限制:它优先保障类型安全与 SQL 注入防护。你不能用 prisma.$queryRaw 去拼接用户输入、也不能绕过参数化机制硬塞字符串。
为什么 prisma.$queryRaw 不等于 “写 SQL”
很多人误以为 $queryRaw 是“执行任意 SQL”的入口,其实它只接受 Prisma.sql 模板字面量——这个模板会强制你把所有动态值作为参数传入,底层自动转义并绑定,根本无法拼接 SQL 片段。
- ✅ 正确:使用
Prisma.sql模板 + 占位符,如Prisma.sql`SELECT * FROM users WHERE name = ${name}` - ❌ 错误:用字符串拼接,如
`SELECT * FROM users WHERE name = '${name}'`——Prisma会直接报错或忽略 - ⚠️ 注意:
$queryRaw返回的是原始行数组(any[]),没有类型推导;若需类型安全,必须手动 cast 或配合$queryRawUnsafe(见下条)
$queryRawUnsafe 的真实用途和风险边界
$queryRawUnsafe 是唯一允许传入字符串 SQL 的 API,但它不是“更自由”,而是“更危险且有明确约束”——它只应在完全可控、无任何外部输入的场景下使用,比如迁移后校验、固定报表语句、或数据库特性探测。
使用 JSON Schema 验证 JSON 数据,从示例 JSON 生成 schema,并将其转换为 TypeScript 接口、Python 数据类或 Markdown 文档。
- 典型安全场景:运行
SELECT version()、SHOW TABLES(MySQL)、SELECT table_name FROM information_schema.tables - 绝对禁止场景:含
req.query.sort、req.body.search、req.params.id等任何请求参数参与拼接 - 替代方案优先级:能用
prisma.user.findMany({ where: { ... } })就别用unsafe;能用Prisma.sql就别降级到unsafe
Node.js 20 下必须检查的兼容点
Node.js 20 默认启用 --enable-source-maps 和更严格的 TLS/HTTP 行为,会影响 Prisma 的底层连接表现,尤其在使用 $queryRaw 类操作时:
-
pg驱动需 ≥ v8.11.0:旧版在 Node.js 20 下可能触发ERR_TLS_CERT_ALTNAME_INVALID(尤其连云 PostgreSQL 如 Supabase/Railway) -
Prisma Client必须 ≥ v5.14.0:早于该版本的$queryRaw在 Node.js 20 的Promise.withResolvers环境中存在竞态 bug,可能导致查询静默失败 - 环境变量
DATABASE_URL中若含特殊字符(如密码含@、/),必须 URL encode:Node.js 20 的URL构造器解析更严格,未编码会导致连接被截断
真正难的不是“怎么写”,而是判断“该不该写”。只要出现“我需要原生 SQL 才能实现”的念头,先花两分钟确认:是不是模型关系没定义好?是不是 include/select 没用对?是不是漏看了 groupBy 或 having?Prisma 的绝大多数“做不到”,其实是没走到它的表达边界内。










