Rust ORM库diesel的安装及使用
最近在用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(控制台命令行接口)
在项目目录执行下面的命令进行安装。
bashcargo install diesel_cli
这里插一嘴,安装的时候我遇到了类似下面模板的报错。
plaintexterror: linking with cc failed: exit code: 1
|
= note: ld: cannot find -lxxx
这个地方也卡了我一会,主要是没懂编译器意思。现在我知道了,以后重点看 note:后面的部分再去网上查。
这个问题的原因一般有以下几种
- 系统缺乏对应的库文件;
- 版本不对应;
- 库文件的链接错误;
- 库文件路径设置问题。
ubuntu大多数可以直接通过apt-get来安装:
bashapt-get install libxxx-dev
解决了这个问题总算是把diesel 和 diesel_cli都装上了。
二、diesel 的使用
这种容易查到的东西不太想多说。我主要是参考的这篇文章。
这里把要用的命令列一下,方便以后自己查阅。
bashdiesel setup
diesel migration generate create_posts
diesel migration run
三、插嘴说下使用mysql时遇到的一个小问题
配置好diesel后我尝试 diesel migration run结果一直报这个错误
plaintextCould 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连接
bashmysql -u root -p
结果还是报一样的错,为什么??
原来,mysql客户端默认采取的是本机连接的方案,而我的宿主机上根本没有安装mysql服务端。
不过,只要指定采用tcp连接的方式即可。如下:
bashmysql -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 构建 :
rustusers
.filter(name.eq("John")) // 类型检查:`name` 必须是 `Text` 类型
.select((id, name)) // 检查字段是否存在
- 编译时验证 :每个方法调用(如
.filter())会向 AST 添加节点,同时检查表达式合法性(例如age.eq("John")会因类型不匹配失败)。 - 零成本抽象 :最终生成的 SQL 与手写效率相同,无运行时开销。
4. 执行查询:从 AST 到安全 SQL
调用 .load() 或 .execute() 时,Diesel 按以下步骤执行:
- SQL 生成 :根据 AST 调用
QueryFragment实现,生成数据库特定的 SQL(如 PostgreSQL 的$1占位符)。 - 参数绑定 :将 Rust 值(如
"John")转换为数据库格式,避免 SQL 注入。 - 结果映射 :通过
Queryable实现将数据库返回的数据反序列化为User实例。
5. 为什么选择 Diesel?与传统方式的对比
| 传统方式的问题 | Diesel 的解决方案 | 优势 |
|---|---|---|
| 手写 SQL 易拼错字段名 | table! 宏生成类型化访问器 |
编译时字段名检查 |
| 手动处理参数绑定与防注入 | 自动参数化查询 | 零 SQL 注入风险 |
| 数据库方言差异(如分页语法) | 统一抽象层 + 多后端支持 | 代码可移植性高 |
| 运行时才发现类型不匹配 | 编译时模型与 Schema 类型校验 | 消灭 90% 的运行时数据库错误 |
总结:ORM 的本质是类型桥梁
Diesel 通过 宏生成 + 类型系统 + 编译时验证 ,在数据库世界与 Rust 代码之间架起一座 类型安全的桥梁 。它的设计哲学是:
“如果代码能编译通过,那么数据库操作一定是正确的” 。
这种编译时保障,加上对运行时性能的零妥协,正是 Rust ORM 的独特魅力所在。
💬 评论区
暂无评论,来发表第一条吧。