03
数据库访问:SQLx 与 SeaORM
SQLx & SeaORM · Compile-time Checked SQL
Rust 数据库圈两大主流:SQLx——你写 SQL,它在编译期帮你检查语法对不对、参数类型对不对,不用 ORM;SeaORM——ActiveRecord 风格的 ORM,类似 Django ORM,不想写 SQL 就用它。本章两个都讲,你按口味选。
SQLx:编译期检查 SQL 的异步数据库库
论SQLx 最爽的一点
普通 ORM 是运行时才发现 SQL 写错了——你接口上线了,用户点一下报 500。SQLx 是编译期就把你的 SQL 发给数据库验证:语法错了、表不存在、列名拼错了、参数类型不匹配,cargo build 直接报错。这是其他语言做梦都想要的能力。
支持 MySQL / PostgreSQL / SQLite,全异步,连接池开箱即用。对标 Java 的 MyBatis,但比 MyBatis 早发现错误十年。
Cargo.toml(以 PostgreSQL 为例)
sqlx = { version = "0.8", features = ["runtime-tokio-rustls", "postgres", "chrono", "uuid", "macros"] }
连接池 + CRUD
use sqlx::{postgres::PgPoolOptions, Row};
use serde::Serialize;
// 实体:用 FromRow derive,行自动映射成结构体
#[derive(Debug, Serialize, sqlx::FromRow)]
struct User {
id: i64,
name: String,
email: String,
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// 1. 创建连接池(对标 HikariCP)
let pool = PgPoolOptions::new()
.max_connections(10)
.connect("postgres://postgres:postgres@localhost/app")
.await?;
// 2. query! 宏:编译期检查 SQL(需要数据库在线或 SQLX_OFFLINE)
let rows = sqlx::query!(
"SELECT id, name, email FROM users WHERE email = $1",
"a@b.com"
).fetch_all(&pool).await?;
for r in rows {
println!("{} {}", r.id, r.name);
}
// 3. query_as! 直接映射到结构体
let user: Option<User> = sqlx::query_as::<_, User>(
"SELECT id, name, email FROM users WHERE id = $1"
).bind(1)
.fetch_optional(&pool)
.await?;
// 4. 事务:begin / commit / rollback(对标 @Transactional)
let mut tx = pool.begin().await?;
sqlx::query("INSERT INTO users(name, email) VALUES ($1, $2)")
.bind("Tom")
.bind("tom@x.com")
.execute(&mut *tx).await?;
tx.commit().await?;
Ok(())
}
sqlx-cli 与离线编译
query! 宏在编译期要连数据库验证 SQL。CI 环境不一定有数据库,这时候用离线模式:本地跑一次 cargo sqlx prepare,把查询缓存到 .sqlx/ 目录,提交到 git。CI 上设 SQLX_OFFLINE=true,就不连数据库也能编译。
# 安装命令行工具
cargo install sqlx-cli --no-default-features --features rustls,postgres
# 创建迁移文件
sqlx migrate add create_users_table
# 执行迁移
sqlx migrate run
# 生成离线查询缓存(CI 前必跑)
cargo sqlx prepare
# CI 上:不连数据库也能编译
SQLX_OFFLINE=true cargo build --release
SeaORM:写不来 SQL 就用 ORM
SeaORM 是 Rust 里最成熟的 ORM,ActiveRecord 风格。定义 Entity,然后用链式 API 查询,不用写一句 SQL。适合业务模型复杂、团队不想写 SQL 的场景。
// src/entity/user.rs —— 定义实体(对标 JPA @Entity)
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize)]
#[sea_orm(table_name = "users")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i64,
pub name: String,
pub email: String,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}
impl ActiveModelBehavior for ActiveModel {}
// 查询:find + filter + order_by + paginate
use sea_orm::{Database, EntityTrait, QueryFilter, QueryOrder, ColumnTrait};
let db = Database::connect("postgres://...").await?;
// WHERE name LIKE '%Tom%' ORDER BY id DESC LIMIT 10
let users = Entity::find()
.filter(Column::Name.contains("Tom"))
.order_by_desc(Column::Id)
.limit(10)
.all(&db).await?;
// 插入一条
let new_user = ActiveModel {
name: Set("Tom".into()),
email: Set("tom@x.com".into()),
..Default::default()
};
new_user.save(&db).await?;
Diesel:老牌编译期查询构建器(了解即可)
Diesel 是 Rust 最早一代数据库生态主力,主打"编译期把查询语法和字段类型全查一遍"。它和 sqlx 的共同点是编译期安全,但路线不同:sqlx 让你写裸 SQL 再校验,Diesel 用 DSL 拼查询。新项目更推荐 sqlx + SeaORM,但面试/老项目可能遇到 Diesel,认得就行。
// Diesel 是同步的(不基于 Tokio),用 schema!! 宏映射表结构
table! users {
id -> Int8,
name -> Varchar,
}
use users::dsl::*;
// DSL 拼查询,类型在编译期就对齐
let results = users
.filter(name.like("%Tom%"))
.order(id.desc())
.limit(10)
.load::<User>(&mut conn)?; // conn 是同步连接
三种数据库栈怎么选
| 栈 | 特点 | 适合 |
| sqlx | 写裸 SQL,编译期校验,异步 | 主力:业务复杂、想掌 SQL |
| SeaORM | ActiveRecord ORM,异步,链式 API | 不想写 SQL、模型驱动 |
| Diesel | DSL 查询构建器,同步,老牌 | 维护老项目;新项目少用 |
NoSQL:Redis 与 MongoDB
| 场景 | 推荐 crate | 说明 |
| Redis 缓存 | redis(带 tokio-comp feature) | 异步客户端,支持 SET/GET/PubSub/Stream |
| MongoDB | mongodb(官方驱动) | 官方维护,异步,BSON 文档模型 |
| 向量检索 | qdrant-client | Rust 写的向量库,AI 页细讲 |
use redis::{AsyncCommands, Client};
let client = Client::open("redis://127.0.0.1/")?;
let mut con = client.get_multiplexed_async_connection().await?;
con::set_ex("greeting", "hello", 60).await?;
let v: String = con::get("greeting").await?;
println!("{v}");
记
本章小结
① SQLx 写 SQL,编译期检查;SeaORM 写 ORM,链式 API。团队里有 SQL 高手就 SQLx,业务模型复杂就 SeaORM。
② 连接池用 PgPoolOptions,事务用 begin()/commit(),迁移用 sqlx migrate,CI 用 SQLX_OFFLINE=true。
③ Redis 用 redis crate,MongoDB 用官方 mongodb crate。