Rust ORM库diesel的安装及使用

2025/3/241835 字

最近在用Rust做项目实现

要用到数据库,本来想用sqlx,因为用着一直不顺利,也一头雾水的,所以就没有用。

最后选择的是diesel这个库,感觉也还是挺成熟的。

一、diesel 以及 diesel_cli 的安装

我是在 Cargo.toml里面添加了下面的两行,个人用着比较习惯。

plaintext
# for database
diesel = { version = "2.0", features = ["sqlite", "mysql", "chrono"] }
chrono = "0.4" # for datetime

然后cargo就会自动开始装diesel的库。

但是要用diesel配置好数据库,把库装好还不够。因为还需要做数据库迁移(migration)的工具(之前用SpringBoot和Django这种集成度很高的框架,根本没想过orm库是怎么实现类和表进行映射和数据库迁移的。不过这下感受到了,这也是Rust利于学习的原因之一——把各种东西都直接摆到你的面前而不是隐藏它)

这个工具就是diesel配套的cli(控制台命令行接口)

在项目目录执行下面的命令进行安装。

bash
cargo install diesel_cli

这里插一嘴,安装的时候我遇到了类似下面模板的报错。

plaintext
error: linking with cc failed: exit code: 1
  |
  = note: ld: cannot find -lxxx

这个地方也卡了我一会,主要是没懂编译器意思。现在我知道了,以后重点看 note:后面的部分再去网上查。

这个问题的原因一般有以下几种

  1. 系统缺乏对应的库文件;
  2. 版本不对应;
  3. 库文件的链接错误;
  4. 库文件路径设置问题。

ubuntu大多数可以直接通过apt-get来安装:

bash
apt-get install libxxx-dev

解决了这个问题总算是把diesel 和 diesel_cli都装上了。

二、diesel 的使用

这种容易查到的东西不太想多说。我主要是参考的这篇文章。

这里把要用的命令列一下,方便以后自己查阅。

bash
diesel setup
diesel migration generate create_posts
diesel migration run

三、插嘴说下使用mysql时遇到的一个小问题

配置好diesel后我尝试 diesel migration run结果一直报这个错误

plaintext
Could not connect to database via `mysql://root:wwee1w2@localhost:3306/information_schema`: Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)

我就很疑惑,我明明就用docker安装了mysql,端口映射也没问题,我还能在主机上用DBeaver访问。

查了一些资料才知道报这个错就意味着本机上没有装mysql客户端,也就是

mysql-client,我才恍然大悟mysql是个C/S架构的软件,只不过平常安装的时候C/S一起被安装到了服务器上,而使用docker安装mysql就会导致宿主机上没有mysql的客户端。

好的,再补装了mysql客户端后,我这次先尝试在宿主机上使用mysql连接

bash
mysql -u root -p

结果还是报一样的错,为什么??

原来,mysql客户端默认采取的是本机连接的方案,而我的宿主机上根本没有安装mysql服务端。

不过,只要指定采用tcp连接的方式即可。如下:

bash
mysql -u root -p -h 127.0.0.1 -P 3306

这下我可以用mysql命令连接docker容器的mysql了,再次尝试 diesel migration run结果又失败了,还是连接不上。

原来如果在url里面如果写的是 localhost,还是会采用本机连接的方式。

解决方式就是把url中的 localhost用 127.0.0.1 代替。

终于,连接成功。

四、diesel 的原理(尝试)理解

下面的内容是我和deepseek交流过后个人比较满意的回答

揭秘 Diesel ORM 的工作原理:如何用 Rust 的类型安全消灭数据库错误

ORM(对象关系映射)的核心目标是建立数据库表与编程语言结构之间的双向映射,让开发者用面向对象的方式操作数据库。Rust 的 Diesel 库通过独特的编译时验证机制,将这一理念提升到了新的高度。以下是它的核心设计原理:


1. 定义表结构:从数据库到代码的强类型映射

Diesel 要求开发者 显式定义数据库表结构 ,这一步通过两种方式协作完成:

  • 迁移脚本(Migrations)
    开发者手动编写 SQL 定义表结构(如 CREATE TABLE users),并通过 diesel-cli 执行迁移。这一步确保数据库的实际结构与代码预期一致。

  • Schema 描述(schema.rs)
    通过 table! 宏生成 Rust 代码,描述表的元信息(列名、类型):

    rust
    // 由 diesel-cli 自动生成
    table! {
        users (id) {
            id -> Integer,
            name -> Text,
        }
    }
    

    关键点 :table! 不是定义模型,而是生成 类型化的列访问器 (如 users::name),后续所有查询将基于这些类型构建。


2. 定义模型:结构体与表的绑定

开发者需手动创建 Rust 结构体,并标记其与表的映射关系:

rust
#[derive(Queryable, Insertable)]
struct User {
    id: i32,
    name: String,
}
  • Queryable :将查询结果反序列化为 User 结构体。
  • Insertable :将 User 实例转换为可插入数据库的数据。
    Diesel 会在编译时检查结构体字段是否与 table! 定义的类型匹配 ,若不一致直接报错。

3. 查询构建:类型安全的抽象语法树(AST)

Diesel 的链式 API(如 .filter()、.select())看似简单,背后是 类型化的 AST 构建 :

rust
users
    .filter(name.eq("John"))  // 类型检查:`name` 必须是 `Text` 类型
    .select((id, name))       // 检查字段是否存在
  • 编译时验证 :每个方法调用(如 .filter())会向 AST 添加节点,同时检查表达式合法性(例如 age.eq("John") 会因类型不匹配失败)。
  • 零成本抽象 :最终生成的 SQL 与手写效率相同,无运行时开销。

4. 执行查询:从 AST 到安全 SQL

调用 .load() 或 .execute() 时,Diesel 按以下步骤执行:

  1. SQL 生成 :根据 AST 调用 QueryFragment 实现,生成数据库特定的 SQL(如 PostgreSQL 的 $1 占位符)。
  2. 参数绑定 :将 Rust 值(如 "John")转换为数据库格式,避免 SQL 注入。
  3. 结果映射 :通过 Queryable 实现将数据库返回的数据反序列化为 User 实例。

5. 为什么选择 Diesel?与传统方式的对比

传统方式的问题 Diesel 的解决方案 优势
手写 SQL 易拼错字段名 table! 宏生成类型化访问器 编译时字段名检查
手动处理参数绑定与防注入 自动参数化查询 零 SQL 注入风险
数据库方言差异(如分页语法) 统一抽象层 + 多后端支持 代码可移植性高
运行时才发现类型不匹配 编译时模型与 Schema 类型校验 消灭 90% 的运行时数据库错误

总结:ORM 的本质是类型桥梁

Diesel 通过 宏生成 + 类型系统 + 编译时验证 ,在数据库世界与 Rust 代码之间架起一座 类型安全的桥梁 。它的设计哲学是:
“如果代码能编译通过,那么数据库操作一定是正确的” 。
这种编译时保障,加上对运行时性能的零妥协,正是 Rust ORM 的独特魅力所在。

💬 评论区

写评论

暂无评论,来发表第一条吧。

© 2026 Corn 的自留地