你以为 ORM 只能靠运行才发现 SQL 写错了?今天 SQLx 用编译期检查把这件事彻底变了
写过 Rust 后端的人都踩过这个坑——SQL 字符串写进代码里,到底有没有语法错误、有没有拼错列名、类型对不对得上,只能等运行的时候数据库报错才恍然大悟。特别是 CI 跑完、上了生产,突然一条查询崩了,那感觉就像考试铃响了才发现答案写在草稿纸上。
这件事被 SQLx 0.9(2026 年 5 月发布)彻底原生化了——它让你写 SQL 不用二选一:要么放弃类型安全靠 ORM,要么放弃 SQL 靠 query builder。SQLx 给你第三条路:直接写 SQL,编译期检查。
query!宏:连接一次数据库,换一辈子的编译时安心
SQLx 的核心是 query! 宏家族。编译时,它会真正连接你的开发数据库(PostgreSQL / MySQL / SQLite),让数据库本身验证 SQL 语法是否正确、列名存不存在、参数类型和返回值能不能对上。整个过程不需要任何 DSL,直接写原始 SQL 字符串:
“`rust
let rec = sqlx::query!(
“SELECT id, name, email FROM users WHERE id = $1”,
user_id
)
.fetch_one(&pool)
.await?;
println!(“{}!”, rec.name);
“`
如果 SQL 有问题——比如 $1 传了 &str 但数据库期待 i64——cargo build 直接失败,报错信息直接告诉你第几行、哪个字段、类型不匹配。数据库连接只在本地编译时用一次,生产构建不需要。
离线模式:CI 构建不需要数据库也能验证
团队协作时,不能要求每个开发者的机器都连着数据库,CI 服务器更不可能。SQLx 支持离线模式:
“`bash
cargo sqlx prepare
SQLX_OFFLINE=true cargo build
“`
每次 schema 变更后跑 cargo sqlx prepare --check,CI 就能发现缓存过期、阻止带病代码合并。「SQL 写错了,上线才知道」变成了「commit 没更新缓存,CI 就拦住」。
Rust 工具链视角:比 ORM 快,比 query builder 安全
| SQLx | Diesel | SeaORM | |
|---|---|---|---|
| 抽象程度 | 直接写 SQL | 类型化 query builder | ORM(关系映射) |
| SQL 检查 | 编译期(需 DB) | 编译期(DSL) | 运行时 |
| 异步 | 原生 async/await | 同步 | 原生 async/await |
| 学习曲线 | 只需懂 SQL | 需学 DSL | 需学 ORM 概念 |
你真正要注意的坑
query! 需要数据库连接才能编译,这意味着没有 .sqlx 缓存时 CI 构建必须有数据库。常见误区是「编译过了就是安全的」——实际上缓存不更新,schema 改了 SQL 没改,还是会放行。建议把 cargo sqlx prepare --check 单独一个 CI job,专门盯缓存有效性。
第二个坑是 nullable 处理:数据库 nullable 字段映射到 Rust 需要用 Option<T>,加了 ? 才不会编译报错。切过来第一天会多不少 ? 操作符,但这是值得的。
下一步
从 cargo install sqlx-cli 开始,跑一次 sqlx database create,在迁移文件里把 schema 定好。schema 敲定了,query! 写 SQL 的时候心里就踏实了——写错了 cargo build 拦住你,不会在凌晨三点让用户看到 500。
评论区
登录后可评论。