Diesel:Rust 语言的编译时安全 ORM

用 Rust 写数据库交互代码,最怕什么?SQL 写错了,跑起来才发现。

Diesel 解决了这个问题。它是 Rust 生态中最成熟的 ORM 和查询构建器,星标超过 14,000。所有 SQL 在编译阶段就会被检查,类型不对直接报错,不会留到运行时。

正文顶部截图

支持三种数据库:PostgreSQL、MySQL、SQLite。

README区域截图

安装

Cargo.toml 中加上依赖:

[dependencies]
diesel = { version = "2.2", features = ["postgres"] }

features 改成 mysqlsqlite 即可切换后端。

基本查询

查全部用户:

users::table.load(&mut connection)

对应生成的 SQL 是 SELECT * FROM users;

按关联关系查询,比如查某个用户的所有文章:

Post::belonging_to(user).load(&mut connection)

生成 SQL:SELECT * FROM posts WHERE user_id = 1;

组合条件查询

嵌套查询、过滤、排序、分页,可以自由组合:

let versions = Version::belonging_to(krate)
  .select(id)
  .order(num.desc())
  .limit(5);
let downloads = version_downloads
  .filter(date.gt(now - 90.days()))
  .filter(version_id.eq_any(versions))
  .order(date)
  .load::<Download>(&mut conn)?;

这段代码生成的 SQL 包含子查询和日期过滤,全部在编译时完成类型校验。

减少样板代码

Diesel 通过 derive 宏自动生成字段映射:

#[derive(Queryable, Selectable)]
#[diesel(table_name = downloads)]
pub struct Download {
    id: i32,
    version_id: i32,
    downloads: i32,
    date: SystemTime,
}

不用 Diesel 的话,你得手动实现一个 from_row 方法,逐字段调用 row.get("xxx"),写起来繁琐且容易出错。

插入数据

定义一个结构体,用 Insertable 标注,直接插入:

#[derive(Insertable)]
#[diesel(table_name = users)]
struct NewUser<'a> {
    name: &'a str,
    hair_color: Option<&'a str>,
}

insert_into(users)
    .values(&new_users)
    .execute(&mut connection);

execute 换成 get_results,还能直接拿到插入后的完整记录。

更新数据

单条修改用 save_changes,批量更新用 update 加过滤条件:

// 单条
post.published = true;
post.save_changes(&mut connection);

// 批量
update(users.filter(email.like("%@spammer.com")))
    .set(banned.eq(true))
    .execute(&mut connection)

原生 SQL

遇到复杂查询写不成构建器语法时,也可以直接写 SQL,通过 sql_query 调用,结果同样映射到结构体。

整体来看,Diesel 的核心价值很清晰:让 Rust 的类型系统帮你在编译阶段就把 SQL 问题拦住,同时省掉大量手动映射的样板代码。对于长期维护的项目来说,这个 compile-time 的保障比写起来方便更重要。

体。

整体来看,Diesel 的核心价值很清晰:让 Rust 的类型系统帮你在编译阶段就把 SQL 问题拦住,同时省掉大量手动映射的样板代码。对于长期维护的项目来说,这个 compile-time 的保障比写起来方便更重要。