Rust数据库与工具的选择
数据库选型:PostgreSQL
选型原则(经验分享):
-
持久化需求不明确: 优先考虑关系型数据库。
-
无大规模扩展预期: 推荐使用 PostgreSQL。
总结而言,当不完全确定应用的数据访问模式时,关系型数据库是一个稳妥且通用的选择。
最终选择及理由:
我们的项目最终选用 PostgreSQL,主要基于以下考虑:
-
成熟可靠: 它是经过实战检验的技术,拥有详尽的文档。
-
生态友好: 得到所有主流云服务商的广泛支持,并且是开源的。
-
开发便捷: 可通过 Docker 轻松在本地和持续集成(CI)环境中运行。
-
技术栈契合: 在我们使用的 Rust 生态系统中拥有良好的支持。
选择数据库包
Rust项目中与PostgreSQL交互时,有三个首选项目
- tokio-postgres;
- sqlx
- diesel;
如何选择呢?取决于你对以下三个话题的看法
- 编译时的安全性
- SQL优先还是用于查询构建的DSL;
- 同步接口还是异步接口
Rust 数据库访问工具对比(tokio-postgres
、sqlx
、diesel
)
与关系型数据库打交道时,我们常犯的错误包括:名称拼写错误、尝试执行数据库不支持的操作(如将文本和数字相加)、以及对返回数据中字段的错误预期。
核心问题:这些错误应该在什么时候被发现?
1. 编译时安全性:提前发现错误
在多数编程语言中,这类错误在运行时发生——即程序执行查询时,数据库拒绝操作并返回错误。tokio-postgres
就是这种模式。
diesel
和 sqlx
则致力于在程序编译阶段就发现并报告这些问题,提供更高的安全性:
-
diesel
:它依赖一个工具,将数据库的结构(模式)转换成 Rust 代码。编译器根据这个结构来验证所有查询的合理性。 -
sqlx
:它在编译时临时连接到数据库。这种连接允许它直接检查你提供的 SQL 语句是否正确、合法。
好处: 错误在程序运行之前就被修正,代码更加可靠。
2. 查询接口:SQL 原生 vs. 查询构建器
SQL 原生
tokio-postgres
和 sqlx
都要求你直接使用标准的 SQL 语句编写查询。
- 优点: SQL 知识具有通用性。无论使用什么编程语言或框架,只要涉及关系型数据库,你都可以应用这套知识。
查询构建器 (DSL)
diesel
则提供了一套自己的“查询构建器”:它通过链式调用 Rust 代码中的方法来构造查询,而不是直接写 SQL。
-
取舍:
-
学习成本(缺点): 这套构建器需要额外学习,知识收益仅限于使用
diesel
的项目。 -
复杂性(缺点): 构造非常复杂的查询时,使用
diesel
的构建器可能很困难,最终你可能仍需回退到原始 SQL。 -
可重用性(优点):
diesel
的查询构建器更容易将复杂逻辑分解成小的、可重复使用的代码片段,就像普通的 Rust 函数一样。
-
3. 异步支持
一个很好的关于异步I/O的解释
线程用于并行工作,异步用于并行等待。
异步 I/O 的理念是:让程序在等待数据库响应时,去做其他有意义的事情。
数据库和应用程序通常不在同一台机器上,运行查询必须等待网络往返时间。
异步驱动程序(tokio-postgres
和 sqlx
支持)不会缩短单个查询所需的时间。
关键在于: 它能让应用程序在等待数据库结果的这段时间,不浪费 CPU 资源。程序可以利用这段时间处理其他用户的请求,从而显著提升应用程序同时处理任务的能力。
一般来说,在单独的线程池上运行查询应该足以满足大多数用例。同时,如果Web框架已经时异步的,那么使用异步数据库驱动程序实际上会让你少一些麻烦。
sqlx和tokio-postgres都提供异步接口,而diesel是同步的,并且没有计划设计出异步的打算。
值得一提的是,tokio-postgres是位于支持查询管道的包。
4. 总结
包 | 编译时的安全性 | 查询接口 | 异步 |
---|---|---|---|
tokio-postgres | 不支持 | SQL | 支持 |
sqlx | 支持 | SQL | 支持 |
diesel | 支持 | DSL | 不支持 |
5. 我们的选择—sqlx
它的异步支持简化了与actix-web的集成,但不会迫使我们在编译时做出妥协。由于它使用原始的SQL语句进行查询,我们只要掌握较少的API即可。