Rust + sqlx:编译期 SQL 校验、连接池与事务管理

test12026-09-122 次阅读

为什么用 sqlx 而不是 ORM

sqlx 是 Rust 的异步 SQL 工具箱,最大卖点是编译期 SQL 校验:在 cargo build 阶段就连接数据库检查你的 SQL 语法和参数数量是否正确,把大量运行时错误提前到编译期。

连接池与编译期校验查询

use sqlx::{PgPool, postgres::PgPoolOptions};

#[derive(sqlx::FromRow)]
struct User {
    id: i64,
    name: String,
}

async fn init_pool() -> anyhow::Result<PgPool> {
    let pool = PgPoolOptions::new()
        .max_connections(10)
        .connect("postgres://user:pass@localhost/db")
        .await?;
    Ok(pool)
}

用宏做编译期校验

query_as! 宏会在编译时连库校验 SELECT 字段与结构体是否匹配。离线构建时用 cargo sqlx prepare 生成 .sqlx 缓存,CI 里不必连真实库。

async fn get_user(pool: &PgPool, id: i64) -> anyhow::Result<Option<User>> {
    let user = sqlx::query_as!(
        User,
        "SELECT id, name FROM users WHERE id = $1",
        id
    )
    .fetch_optional(pool)
    .await?;
    Ok(user)
}

事务保证一致性

转账这类多步写操作必须放进事务。sqlx 的事务 API 与连接池无缝衔接,commit 失败自动回滚。

async fn transfer(pool: &PgPool, from: i64, to: i64, amount: i64) -> anyhow::Result<()> {
    let mut tx = pool.begin().await?;
    sqlx::query("UPDATE accounts SET balance = balance - $1 WHERE id = $2")
        .bind(amount).bind(from)
        .execute(&mut *tx).await?;
    sqlx::query("UPDATE accounts SET balance = balance + $1 WHERE id = $2")
        .bind(amount).bind(to)
        .execute(&mut *tx).await?;
    tx.commit().await?;
    Ok(())
}

要点

  • query_as! 在编译期校验 SQL,字段对不上直接编译失败。
  • 连接池用 PgPoolOptions 配置上限,避免连接泄漏。
  • 多步写操作包进事务,保证原子性。
  • 离线 CI 用 cargo sqlx prepare 配合 SQLX_OFFLINE=true。
T

test1

文章作者

为什么用 sqlx 而不是 ORM sqlx 是 Rust 的异步 SQL 工具箱,最大卖点是编译期 SQL 校验:在...

分类
技术
发布时间
2026-09-12
字数
约 1492 字
阅读
2 次