0Pricing
Learn Rust Coding · 课时

CRUD 操作

查询与执行

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

使用 sqlx 实现 CRUD

CRUD 代表创建、读取、更新和删除。sqlx 将这些操作分为两种执行方式:

  • fetch_* 用于返回行的查询
  • execute 用于修改数据的语句

创建(INSERT)

使用绑定参数插入一行,并通过 execute 执行。使用 RETURNING 获取生成的 id。

use sqlx::{Pool, Postgres};

async fn create(pool: &Pool<Postgres>, name: &str) -> i32 {
    let rec = sqlx::query!(
        "INSERT INTO users (name) VALUES ($1) RETURNING id",
        name
    ).fetch_one(pool).await.unwrap();
    rec.id
}

读取一行

fetch_one 要求恰好返回一行,否则会报错。当该行可能不存在时,请使用 fetch_optional。

use sqlx::{Pool, Postgres};

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

读取多行

fetch_all 返回所有匹配行组成的 Vec。

use sqlx::{Pool, Postgres};

async fn all_names(pool: &Pool<Postgres>) -> Vec<String> {
    let rows = sqlx::query!("SELECT name FROM users ORDER BY id")
        .fetch_all(pool)
        .await
        .unwrap();
    rows.into_iter().map(|r| r.name).collect()
}

更新

UPDATE 语句使用 execute,它会返回一个结果,其中包含受影响的行数。

use sqlx::{Pool, Postgres};

async fn rename(pool: &Pool<Postgres>, id: i32, name: &str) -> u64 {
    let res = sqlx::query!("UPDATE users SET name = $1 WHERE id = $2", name, id)
        .execute(pool)
        .await
        .unwrap();
    res.rows_affected()
}

删除

DELETE 同样使用 execute。检查 rows_affected(),即可知道是否删除了任何内容。

use sqlx::{Pool, Postgres};

async fn delete(pool: &Pool<Postgres>, id: i32) -> bool {
    let res = sqlx::query!("DELETE FROM users WHERE id = $1", id)
        .execute(pool)
        .await
        .unwrap();
    res.rows_affected() > 0
}

使用纯 Rust 模拟 CRUD

针对内存映射执行 CRUD,与 sqlx 针对数据表执行的相同操作相对应。

use std::collections::HashMap;

fn main() {
    let mut users: HashMap<i32, String> = HashMap::new();
    users.insert(1, "Alice".to_string());      // create
    println!("{:?}", users.get(&1));            // read
    users.insert(1, "Alicia".to_string());      // update
    println!("{:?}", users.get(&1));
    users.remove(&1);                            // delete
    println!("{:?}", users.get(&1));
}

事务

使用事务以原子方式组合多个语句。所有语句要么在 commit 时全部成功,要么全部不生效。

use sqlx::{Pool, Postgres};

async fn transfer(pool: &Pool<Postgres>) {
    let mut tx = pool.begin().await.unwrap();
    sqlx::query!("UPDATE acct SET bal = bal - 10 WHERE id = 1")
        .execute(&mut *tx).await.unwrap();
    sqlx::query!("UPDATE acct SET bal = bal + 10 WHERE id = 2")
        .execute(&mut *tx).await.unwrap();
    tx.commit().await.unwrap();
}

回滚

如果事务保护对象在未调用 commit 的情况下被丢弃,sqlx 会自动回滚。您也可以显式调用 rollback。

use sqlx::{Pool, Postgres};

async fn maybe(pool: &Pool<Postgres>, ok: bool) {
    let mut tx = pool.begin().await.unwrap();
    sqlx::query!("INSERT INTO log (msg) VALUES ('x')").execute(&mut *tx).await.unwrap();
    if ok { tx.commit().await.unwrap(); } else { tx.rollback().await.unwrap(); }
}

流式读取大量数据

对于非常大的结果集,fetch 会返回一个流,让您可以逐行处理,而无需将所有数据加载到内存中。

use sqlx::{Pool, Postgres};
use futures::TryStreamExt;

async fn stream(pool: &Pool<Postgres>) {
    let mut rows = sqlx::query!("SELECT id FROM big_table").fetch(pool);
    while let Some(row) = rows.try_next().await.unwrap() {
        println!("id {}", row.id);
    }
}

处理错误

数据库调用会返回 Result。在返回 Result<_, sqlx::Error> 的函数中,请使用 ? 传播错误,而不要使用解包操作。

use sqlx::{Pool, Postgres};

async fn count(pool: &Pool<Postgres>) -> Result<i64, sqlx::Error> {
    let rec = sqlx::query!("SELECT COUNT(*) as n FROM users")
        .fetch_one(pool)
        .await?;
    Ok(rec.n.unwrap_or(0))
}

快速检查

检验您对 CRUD 操作的理解。

回顾

您已经学习了使用 sqlx 实现 CRUD:

  • fetch_one、fetch_optional 和 fetch_all 用于读取行
  • execute 用于修改数据,并报告 rows_affected()
  • RETURNING 用于获取生成的值
  • 使用 begin/commit/rollback 的事务可确保原子性

下一步:使用迁移演进架构。

常见问题解答

「CRUD 操作」课时是免费的吗?

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

「CRUD 操作」这节课中我会学到什么?

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

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

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

「CRUD 操作」课时需要多长时间?

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

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

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

此课程中的所有课时

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