0Pricing
Learn Rust Coding · 课时

编译期检查查询

类型安全的 SQL

编译期检查查询 是 CoddyKit 上的免费 Learn Rust Coding 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Learn Rust Coding 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Learn Rust Coding 课程共包含 4 节课。

核心优势

sqlx 可以在编译时根据真实数据库架构验证您的 SQL。拼写错误、错误的列名和类型不匹配都会变成构建错误。

  • 使用 query! 宏系列
  • 在运行时之前捕获错误

query! 与 query

query() 函数会在运行时检查。query! 宏会在构建期间连接数据库,从而在编译时检查。

use sqlx::{Pool, Postgres};

async fn run(pool: &Pool<Postgres>) {
    let rec = sqlx::query!("SELECT id, name FROM users WHERE id = $1", 1i32)
        .fetch_one(pool)
        .await
        .unwrap();
}

类型化的结果字段

query! 宏会生成一个匿名结构体,其字段与选中的列相匹配,并根据架构推断出正确的 Rust 类型。

use sqlx::{Pool, Postgres};

async fn name_of(pool: &Pool<Postgres>, id: i32) -> String {
    let rec = sqlx::query!("SELECT name FROM users WHERE id = $1", id)
        .fetch_one(pool)
        .await
        .unwrap();
    rec.name
}

检查的工作方式

构建时,sqlx 需要一个可用的 DATABASE_URL,或者一个已缓存的 .sqlx 目录。它会将查询发送到数据库,以了解参数和结果的类型。

使用 cargo sqlx prepare 的离线模式

对于没有数据库的持续集成环境,请运行 cargo sqlx prepare,将查询元数据保存到 .sqlx/ 中。之后构建过程会使用该缓存。

cargo sqlx prepare

将 query_as! 映射到您的结构体

使用 query_as! 将行直接映射到您定义的结构体中,同时仍然进行完整检查。

use sqlx::{Pool, Postgres};

struct User { id: i32, name: String }

async fn get(pool: &Pool<Postgres>) -> User {
    sqlx::query_as!(User, "SELECT id, name FROM users WHERE id = $1", 1i32)
        .fetch_one(pool)
        .await
        .unwrap()
}

可空列会变成 Option

如果某列可能为 NULL,sqlx 会将对应字段设为 Option。您可以使用 name as "name!" 这样的类型注解覆盖推断结果。

use sqlx::{Pool, Postgres};

async fn maybe_email(pool: &Pool<Postgres>) -> Option<String> {
    let rec = sqlx::query!("SELECT email FROM users WHERE id = $1", 1i32)
        .fetch_one(pool)
        .await
        .unwrap();
    rec.email
}

模拟类型推断

编译时检查会将 SQL 类型映射为 Rust 类型。这个可运行示例模拟了这一映射决策。

fn rust_type(sql: &str, nullable: bool) -> String {
    let base = match sql {
        "int4" => "i32",
        "text" => "String",
        "bool" => "bool",
        _ => "unknown",
    };
    if nullable { format!("Option<{}>", base) } else { base.to_string() }
}

fn main() {
    println!("{}", rust_type("int4", false));
    println!("{}", rust_type("text", true));
}

您将看到的编译错误

如果引用了不存在的列,sqlx 会显示清晰的消息并使构建失败。这种安全性正是这些宏的全部意义。

  • 列名错误 → 编译时错误
  • 类型不匹配 → 编译时错误

绑定参数按位置对应

对于 Postgres,请使用 $1、$2 占位符。sqlx 会根据架构检查每个绑定参数的类型。

use sqlx::{Pool, Postgres};

async fn search(pool: &Pool<Postgres>, name: &str, min_age: i32) {
    let _ = sqlx::query!(
        "SELECT id FROM users WHERE name = $1 AND age >= $2",
        name, min_age
    ).fetch_all(pool).await.unwrap();
}

何时使用非宏形式

对于在运行时构建的动态 SQL(事先不知道列),请使用 query() / query_as()。这样会牺牲编译时检查,换取灵活性。

use sqlx::{Pool, Postgres};

async fn dynamic(pool: &Pool<Postgres>, sql: &str) {
    let _ = sqlx::query(sql).execute(pool).await.unwrap();
}

快速检查

检验您对编译时检查的理解。

回顾

您已经学习了编译时检查的查询:

  • query! 和 query_as! 会在构建时根据架构验证 SQL
  • 结果字段及其类型会自动推断
  • 可空列会变成 Option
  • cargo sqlx prepare 支持离线构建
  • 对于动态 SQL,请使用非宏形式的 query()

下一步:CRUD 操作。

常见问题解答

「编译期检查查询」课时是免费的吗?

是的 — 「编译期检查查询」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Learn Rust Coding 课程的其余内容,请升级到 CoddyKit PRO。 Learn Rust Coding 课程共包含 4 节课。

「编译期检查查询」这节课中我会学到什么?

类型安全的 SQL 你通过在浏览器中直接运行的动手代码来练习 Learn Rust Coding,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Learn Rust Coding 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Learn Rust Coding 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「编译期检查查询」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Learn Rust Coding 课中编写并运行代码吗?

能。每节 Learn Rust Coding 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 连接数据库
  2. 编译期检查查询
  3. CRUD 操作
  4. 迁移
← 返回 Learn Rust Coding