数据库集成(SQLx/Diesel)
使用 SQLx 或 Diesel 等常用对象关系映射工具或查询构建器,将 Rust Web 服务接入数据库。
数据库集成(SQLx/Diesel) 是 CoddyKit 上的免费 Learn Rust Coding 课时。 这是第 2 节课,共 3 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Learn Rust Coding 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Learn Rust Coding 课程共包含 3 节课。
为什么 Web 应用需要数据库?
Web 服务通常需要持久化存储和检索数据。想一想用户资料、产品目录或博客文章——这些数据需要存放在程序内存之外的某个地方。
数据库提供了一种结构化的数据管理方式,确保数据安全、一致且可访问。对于大多数实际应用程序而言,将 Rust Web 服务与数据库集成是一项核心任务。
SQLx:您的异步数据库助手
在 Rust 中,我们有许多优秀的数据库交互工具。两个常用的选择是 SQLx 和 Diesel。
- SQLx:一个异步的纯 Rust SQL crate,其查询会在编译时进行检查。对于使用 Tokio 等框架构建的异步 Web 服务,它通常是首选。
- Diesel:一个功能强大的 ORM(对象关系映射器),提供了更抽象的数据库交互方式,可以将 Rust 结构体直接映射到数据库表。它通常是同步的。
在本课程中,我们将重点介绍 SQLx,因为它对异步操作提供了强有力的支持,非常符合现代 Rust Web 服务的开发方式。
SQLx 设置:依赖项
在编写代码之前,您需要将 sqlx 和 tokio 添加到项目的 Cargo.toml 中。tokio 提供了 sqlx 所需的异步运行时。
例如,要使用 SQLite(一个适合本地开发的基于文件的简易数据库)和 SQLx,您的 Cargo.toml 可能如下所示:
[dependencies]
sqlx = { version = "0.7", features = ["runtime-tokio-rustls", "sqlite"] }
tokio = { version = "1", features = ["full"] }此外,您通常还会使用 DATABASE_URL 环境变量来配置数据库连接字符串。
连接到您的第一个数据库
让我们连接到一个内存中的 SQLite 数据库。SQLx 使用连接池,高效地管理多个数据库连接,以处理 Web 服务中的并发请求。
请尝试运行以下示例:
use sqlx::SqlitePool;
use tokio;
#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
// Use an in-memory SQLite database for simplicity
let database_url = "sqlite::memory:";
let pool = SqlitePool::connect(&database_url).await?;
println!("Successfully connected to the database!");
// In a real web app, 'pool' would be passed around or stored in app state.
Ok(())
}使用表组织数据
在存储数据之前,我们需要使用 DDL(数据定义语言)定义数据库架构。让我们创建一个简单的 tasks 表。
sqlx::query! 宏允许您直接将 SQL 嵌入 Rust 代码中。它甚至会在编译时检查您的 SQL!
use sqlx::{SqlitePool, query};
use tokio;
#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
let database_url = "sqlite::memory:";
let pool = SqlitePool::connect(&database_url).await?;
// Create a 'tasks' table if it doesn't exist
query!(
"CREATE TABLE IF NOT EXISTS tasks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
description TEXT NOT NULL,
completed BOOLEAN NOT NULL DEFAULT FALSE
)"
).execute(&pool).await?;
println!("Table 'tasks' created successfully!");
Ok(())
}添加新记录
现在我们已经有了一个表,让我们添加一些数据!我们将结合参数绑定使用 INSERT 语句。这可以防止 SQL 注入,让您的查询更加安全。
请注意,参数使用 ? 占位符,值则传递给 .bind()。
use sqlx::{SqlitePool, query};
use tokio;
#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
let database_url = "sqlite::memory:";
let pool = SqlitePool::connect(&database_url).await?;
query!(
"CREATE TABLE IF NOT EXISTS tasks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
description TEXT NOT NULL,
completed BOOLEAN NOT NULL DEFAULT FALSE
)"
).execute(&pool).await?;
// Insert a new task
let description = "Learn SQLx";
let completed = false;
query!(
"INSERT INTO tasks (description, completed) VALUES (?, ?)",
description,
completed
).execute(&pool).await?;
println!("Task '{}' inserted successfully!", description);
Ok(())
}使用 SELECT 获取数据
要从 tasks 表中获取数据,我们使用 SELECT 语句。SQLx 提供了 .fetch_all() 和 .fetch_one() 等方法来获取结果。
您可以遍历返回的行,并通过名称或索引访问列。
use sqlx::{SqlitePool, query};
use tokio;
#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
let database_url = "sqlite::memory:";
let pool = SqlitePool::connect(&database_url).await?;
query!(
"CREATE TABLE IF NOT EXISTS tasks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
description TEXT NOT NULL,
completed BOOLEAN NOT NULL DEFAULT FALSE
)"
).execute(&pool).await?;
query!(
"INSERT INTO tasks (description, completed) VALUES (?, ?)",
"Learn SQLx", false
).execute(&pool).await?;
query!(
"INSERT INTO tasks (description, completed) VALUES (?, ?)",
"Build a web app", false
).execute(&pool).await?;
// Fetch and print all tasks
println!("\n--- All Tasks ---");
let rows = query!("SELECT id, description, completed FROM tasks")
.fetch_all(&pool).await?;
for row in rows {
println!("ID: {}, Desc: {}, Done: {}",
row.id, row.description, row.completed);
}
Ok(())
}使用结构体实现类型安全的数据处理
手动从行中提取数据容易出错。SQLx 的 query_as! 宏结合 #[derive(FromRow)],可以将查询结果直接映射到 Rust 结构体中!
这能提供强大的类型安全性,并让代码更加整洁、易于使用。
use sqlx::{FromRow, SqlitePool, query, query_as};
use tokio;
#[derive(Debug, FromRow)]
struct Task {
id: i64,
description: String,
completed: bool,
}
#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
let database_url = "sqlite::memory:";
let pool = SqlitePool::connect(&database_url).await?;
query!(
"CREATE TABLE IF NOT EXISTS tasks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
description TEXT NOT NULL,
completed BOOLEAN NOT NULL DEFAULT FALSE
)"
).execute(&pool).await?;
query!(
"INSERT INTO tasks (description, completed) VALUES (?, ?)",
"Learn SQLx", false
).execute(&pool).await?;
// Fetch tasks directly into our Task struct
println!("\n--- Tasks as Structs ---");
let tasks = query_as::<_, Task>("SELECT id, description, completed FROM tasks")
.fetch_all(&pool).await?;
for task in tasks {
println!("{:?}", task);
}
Ok(())
}修改与删除记录
更新和删除数据的方式与插入类似。您需要结合参数绑定使用 UPDATE 和 DELETE SQL 语句。
- UPDATE:根据
WHERE子句修改现有行。 - DELETE:根据
WHERE子句删除行。
使用 UPDATE 和 DELETE 时,请务必谨慎编写 WHERE 子句,以免意外丢失数据!
use sqlx::{SqlitePool, query};
use tokio;
#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
let database_url = "sqlite::memory:";
let pool = SqlitePool::connect(&database_url).await?;
query!(
"CREATE TABLE IF NOT EXISTS tasks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
description TEXT NOT NULL,
completed BOOLEAN NOT NULL DEFAULT FALSE
)"
).execute(&pool).await?;
query!(
"INSERT INTO tasks (description, completed) VALUES (?, ?)",
"Finish lesson", false
).execute(&pool).await?;
let task_id_to_update = 1;
// Update a task
query!(
"UPDATE tasks SET completed = ? WHERE id = ?",
true,
task_id_to_update
).execute(&pool).await?;
println!("Task {} updated.", task_id_to_update);
// Delete a task (uncomment to run, careful with IDs after update)
// let task_id_to_delete = 1;
// query!(
// "DELETE FROM tasks WHERE id = ?",
// task_id_to_delete
// ).execute(&pool).await?;
// println!("Task {} deleted.", task_id_to_delete);
Ok(())
}检验您的数据库技能
以下哪些陈述是关于 Rust Web 服务中 SQLx 的 TRUE 说法?
数据库集成:要点回顾
通过学习数据库集成,您在构建稳健的 Rust Web 服务方面迈出了一大步!
- 持久化:数据库对于存储应用程序数据至关重要。
- SQLx:一个异步且在编译时进行检查的 SQL crate,非常适合 Web 服务。
- 连接池:对于高效并发地访问数据库至关重要。
- CRUD:我们介绍了创建(
INSERT)、获取(SELECT)、更新(UPDATE)和删除(DELETE)数据。 - 类型安全:
query_as!和#[derive(FromRow)]可以实现安全且便捷的数据映射。
接下来,您可以探索如何将这些数据库操作集成到实际的 Web 路由中!
常见问题解答
「数据库集成(SQLx/Diesel)」课时是免费的吗?
是的 — 「数据库集成(SQLx/Diesel)」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Learn Rust Coding 课程的其余内容,请升级到 CoddyKit PRO。 Learn Rust Coding 课程共包含 3 节课。
「数据库集成(SQLx/Diesel)」这节课中我会学到什么?
使用 SQLx 或 Diesel 等常用对象关系映射工具或查询构建器,将 Rust Web 服务接入数据库。 你通过在浏览器中直接运行的动手代码来练习 Learn Rust Coding,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Learn Rust Coding 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Learn Rust Coding 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 3 节。
「数据库集成(SQLx/Diesel)」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Learn Rust Coding 课中编写并运行代码吗?
能。每节 Learn Rust Coding 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 使用 Actix-web/Rocket 构建 REST API
- 数据库集成(SQLx/Diesel)
- 身份验证与授权