Rust 用 diesel 构建类型安全的数据访问层
test12026-09-274 次阅读
diesel 的定位
sqlx 是运行时校验 SQL,diesel 则把表结构编译进类型系统:字段名、列类型、插入与查询都在编译期检查,拼错列名或类型不匹配会直接编译失败。它生成的 SQL 可控、零额外运行时反射,适合对性能与正确性都有要求的数据访问层。
定义表结构与模型
table! 宏从数据库视角声明表,模型结构用 Queryable 映射查询结果、Insertable 映射写入、Selectable 支撑类型安全的查询构造。
use diesel::prelude::*;
table! {
users (id) {
id -> Int4,
name -> Varchar,
email -> Varchar,
created_at -> Timestamptz,
}
}
#[derive(Queryable, Selectable, Debug)]
#[diesel(table_name = users)]
struct User {
id: i32,
name: String,
email: String,
created_at: chrono::DateTime<chrono::Utc>,
}
#[derive(Insertable)]
#[diesel(table_name = users)]
struct NewUser<'a> {
name: &'a str,
email: &'a str,
}
建立连接与迁移
连接用 PgConnection,生产环境应换成带连接池的 r2d2 或 bb8。迁移文件由 diesel_cli 生成,保证各环境 schema 一致。
use diesel::pg::PgConnection;
use diesel::Connection;
fn connect() -> PgConnection {
PgConnection::establish("postgres://user:pass@localhost/app")
.expect("无法连接数据库")
}
查询与写入
插入用 insert_into 配合 NewUser,返回自增主键;查询用 filter 与 load 把结果映射成 User 向量。
use crate::schema::users::dsl::*;
fn create_user(conn: &mut PgConnection, name: &str, email: &str) -> User {
let new_user = NewUser { name, email };
diesel::insert_into(users)
.values(&new_user)
.get_result(conn)
.expect("插入用户失败")
}
fn active_users(conn: &mut PgConnection) -> Vec<User> {
users
.filter(email.like("%@example.com"))
.order(created_at.desc())
.limit(20)
.select(User::as_select())
.load(conn)
.expect("查询失败")
}
关联查询
多表关联用 belongs_to 与 join。下面给 posts 表声明它属于 users,再用 inner_join 一次性取出作者信息。
table! {
posts (id) {
id -> Int4,
user_id -> Int4,
title -> Varchar,
}
}
#[derive(Queryable, Selectable)]
#[diesel(table_name = posts)]
struct Post {
id: i32,
user_id: i32,
title: String,
}
fn posts_with_author(conn: &mut PgConnection) -> Vec<(Post, User)> {
posts
.inner_join(users)
.select((Post::as_select(), User::as_select()))
.load(conn)
.expect("联表查询失败")
}
- 表宏与实际库表结构必须一致,靠迁移文件单向保证。
- 编译期就能发现的 SQL 错误,省去大量联调时间。
- 生产连接务必走连接池,别每次请求都建立新连接。
T
test1
文章作者
diesel 的定位 sqlx 是运行时校验 SQL,diesel 则把表结构编译进类型系统:字段名、列类型、插入与查...
- 分类
- 技术
- 发布时间
- 2026-09-27
- 字数
- 约 2237 字
- 阅读
- 4 次
