资讯详情

Rocket 实战:用 SQLx、rusqlite 与 Diesel 构建多数据库 JSON 博客 API

📅 2026/9/20 12:52:14 | 华诺云谱 👁 阅读
Rocket 实战:用 SQLx、rusqlite 与 Diesel 构建多数据库 JSON 博客 API
后端开发工具【免费下载链接】RocketA web framework for Rust.项目地址https://gitcode.com/gh_mirrors/ro/Rocket点击查看免费下载本指南围绕 Rocket 官方示例examples/databases展开完整讲解如何在同一个 Rocket 应用中同时接入 SQLite 与 MySQL并以四种主流 Rust 数据库驱动SQLx、rusqlite、Diesel、diesel-async分别实现一套 JSON 博客 CRUD API。读完本文你将掌握 Rocket 数据库连接池rocket_db_pools与rocket_sync_db_pools的配置方式、#[database]派生宏与请求守卫的使用、迁移脚本的组织与自动执行以及使用httpie联调 API 的完整流程。示例概览一个驱动四种写法的博客APIexamples/databases是 Rocket 仓库中用于演示数据库集成的官方示例。它实现了一个基于 JSON 的博客 HTTP API核心数据结构为一张posts表id、title、text、published字段并针对同一条业务逻辑用四种驱动各实现一遍便于对比 API 形态与编码风格驱动数据库挂载路径源码文件sqlx异步SQLite/sqlxsrc/sqlx.rsrusqlite同步经rocket_sync_db_pools包装SQLite/rusqlitesrc/rusqlite.rsdiesel同步SQLite/dieselsrc/diesel_sqlite.rsdiesel-async异步MySQL/mysqlsrc/diesel_mysql.rs从主入口可以看出四个驱动分别通过stage()函数以AdHocFairing 挂载根路径/重定向到/sqlx#[launch] fn rocket() - _ { rocket::build() .mount(/, routes![index]) .attach(sqlx::stage()) .attach(rusqlite::stage()) .attach(diesel_sqlite::stage()) .attach(diesel_mysql::stage()) }环境准备安装 SQLite 与 MySQL 客户端运行本示例前需要本机具备 SQLite 与 MySQL 的开发库/客户端不同平台安装命令如下摘自官方 README# macOS brew install sqlite mysql-client # Debian / Ubuntu apt-get install libsqlite3-dev libmysqlclient-dev # Arch pacman -S sqlite libmysqlclient注意 Debian/Ubuntu 安装的是开发头文件-dev包因为 Rust 依赖需要链接原生库才能编译。API 设计与联调httpie 五类端点四种驱动暴露的端点语义完全一致只是挂载前缀不同。以/sqlx为例完整 API 如下方法路径功能POST/sqlx通过 JSON 提交title、text创建文章返回含新id的文章 JSONGET/sqlx返回所有文章 ID 的 JSON 数组GET/sqlx/id返回指定id文章的对象DELETE/sqlx清空全部文章DELETE/sqlx/id删除指定id的文章原文档使用httpie作为命令行客户端给出完整示例可直接照搬运行把driver换成sqlx、rusqlite、diesel或mysql即可# 创建文章返回含新 id 的 JSON http http://127.0.0.1:8000/sqlx titleTitle textHello, world. { id: 2128, text: Hello, world., title: Title } # 列出全部文章 ID http http://127.0.0.1:8000/sqlx [ 2128, 2129, 2130, 2131 ] # 读取单篇文章 http http://127.0.0.1:8000/sqlx/2128 { id: 2128, text: Hello, world., title: Title } # 清空所有文章 http delete http://127.0.0.1:8000/sqlx # 删除指定文章 http delete http://127.0.0.1:8000/sqlx/4数据库配置Rocket.toml 与连接池参数数据库连接统一在 Rocket.toml 的[default.databases.*]段中声明Rocket 会在启动阶段据此初始化连接池[default.databases.rusqlite] url file:rusqlite?modememorycacheshared [default.databases.sqlx] url db/sqlx/db.sqlite [default.databases.diesel] url db/diesel/db.sqlite timeout 10 [default.databases.diesel_mysql] url mysql://user:password127.0.0.1/database几点说明依据rocket_db_pools的实现文档url是唯一必填项其余参数如min_connections、max_connections、connect_timeout、idle_timeout都有默认值、可选rusqlite使用了内存共享缓存连接串file:rusqlite?modememorycacheshared即每次启动在内存中重建数据库建表逻辑见下文init_dbdiesel_mysql的 URL 采用标准 MySQL 连接串格式mysql://用户:密码主机/库名运行前需替换为真实账号除 TOML 外也支持环境变量注入例如ROCKET_DATABASES{db_name{urldb.sqlite,idle_timeout120}}。从 Cargo.toml 可见驱动依赖的开启方式异步侧使用rocket_db_poolsfeatures 为sqlx_sqlite与diesel_mysql同步侧使用rocket_sync_db_poolsfeatures 为diesel_sqlite_pool与sqlite_pool同时直接依赖sqlx 0.8开启macros、migrate特性以使用query!宏与migrate!宏。四种驱动实现对比SQLx异步 SQLitesrc/sqlx.rs 使用rocket_db_pools的#[derive(Database)]派生连接池并以ConnectionDb作为请求守卫自动取连接#[derive(Database)] #[database(sqlx)] struct Db(sqlx::SqlitePool); #[post(/, data post)] async fn create(mut db: ConnectionDb, mut post: JsonPost) - ResultCreatedJsonPost { let results sqlx::query!( INSERT INTO posts (title, text) VALUES (?, ?) RETURNING id, post.title, post.text ) .fetch(mut **db) .try_collect::Vec_() .await?; post.id Some(results.first().expect(returning results).id); Ok(Created::new(/).body(post)) }实现细节值得注意ConnectionDb解引用mut **db后即为sqlx::pool::PoolConnectionSqlite可直接交给 sqlx 执行查询源码注释提示受 sqlx 上游 issue#2543、#1648影响这里使用fetch try_collect而非更简洁的fetch_one#[serde(crate rocket::serde)]让Post直接复用 Rocket 重导出的 serde避免版本冲突迁移通过sqlx::migrate!(db/sqlx/migrations)在try_on_igniteFairing 中自动执行见run_migrations。rusqlite同步 SQLite经rocket_sync_db_poolssrc/rusqlite.rs 展示的是同步驱动的接入方式#[database(rusqlite)]包一层rusqlite::Connection通过Db::fairing()挂载、Db作请求守卫再经db.run(|conn| ...)在异步运行时中安全执行同步代码#[database(rusqlite)] struct Db(rusqlite::Connection); #[post(/, data post)] async fn create(db: Db, mut post: JsonPost) - ResultCreatedJsonPost { let item post.clone(); let id db.run(move |conn| { conn.query_row(INSERT INTO posts (title, text) VALUES (?1, ?2) RETURNING id, params![item.title, item.text], |r| r.get(0)) }).await?; post.id Some(id); Ok(Created::new(/).body(post)) }由于示例为内存库建表工作放在init_db中启动时通过AdHoc::on_ignite(Rusqlite Init, init_db)执行CREATE TABLE posts (...)id INTEGER PRIMARY KEY AUTOINCREMENT等保证每次进程启动后表结构就绪。Diesel同步 SQLitesrc/diesel_sqlite.rs 采用 Diesel 的类型安全 DSLPost同时派生Queryable与Insertable并通过diesel::table!在代码内声明表结构#[database(diesel)] struct Db(diesel::SqliteConnection); #[post(/, data post)] async fn create(db: Db, mut post: JsonPost) - ResultCreatedJsonPost { let post_value post.clone(); let id: Optioni32 db.run(move |conn| { diesel::insert_into(posts::table) .values(*post_value) .returning(posts::id) .get_result(conn) }).await?; post.id Some(id.expect(returning guarantees id present)); Ok(Created::new(/).body(post)) }创建时依赖 Diesel 2 的RETURNING子句因此 Cargo.toml 中启用了returning_clauses_for_sqlite_3_35特性读取用posts::table.filter(posts::id.eq(id)).first(conn)。迁移则由embed_migrations!(db/diesel/migrations)内嵌并自动执行。diesel-async异步 MySQLsrc/diesel_mysql.rs 演示了异步 Diesel 直连 MySQLDb(MysqlPool)同样由#[derive(Database)]生成请求守卫改为ConnectionDb并把id字段升级为Optioni64MySQL 的BigInt。由于 MySQL 的INSERT不支持RETURNING这里改用事务内last_insert_id()函数取回自增主键#[post(/, data post)] async fn create(mut db: ConnectionDb, mut post: JsonPost) - ResultCreatedJsonPost { diesel::define_sql_function!(fn last_insert_id() - BigInt); let post db.transaction(|mut conn| Box::pin(async move { diesel::insert_into(posts::table) .values(*post) .execute(mut conn) .await?; post.id Some(posts::table .select(last_insert_id()) .first(mut conn) .await?); Ok::_, diesel::result::Error(post) })).await?; Ok(Created::new(/).body(post)) }迁移部分也是异步示例的亮点run_pending_migrations是阻塞调用源码明确注释其必须放入rocket::tokio::task::spawn_blocking中执行以免阻塞异步运行时——这正是异步数据库驱动集成的关键工程细节。迁移Migrations的组织与执行所有迁移文件按驱动存放在examples/databases/db/${driver}目录下db/ ├── diesel/ │ ├── migrations/ # Diesel SQLite 迁移 │ │ └── 20210329150332_create_posts_table/{up.sql, down.sql} │ └── mysql-migrations/ # Diesel MySQL 迁移 │ └── 20210329150332_create_posts_table/{up.sql, down.sql} └── sqlx/ └── migrations/ # SQLx 迁移 └── 20210331024424_create-posts-table.sql三套迁移的建表 SQL 完全一致见 up.sql 与 create-posts-table.sqlCREATE TABLE posts ( id INTEGER PRIMARY KEY AUTOINCREMENT, title VARCHAR NOT NULL, text VARCHAR NOT NULL, published BOOLEAN NOT NULL DEFAULT 0 );本示例中迁移会在应用点火ignite阶段自动执行无需手动干预。原文档也给出了手动执行与准备离线查询元数据的命令# DieselSQLite手动 redo 迁移 cargo install diesel_cli --no-default-features --features sqlite DATABASE_URLdb/diesel/db.sqlite diesel migration --migration-dir db/diesel/migrations redo # SQLx为离线编译cargo sqlx prepare准备查询元数据 cargo install sqlx-cli --no-default-features --features sqlite DATABASE_URLsqlite:$(pwd)/db/sqlx/db.sqlite cargo sqlx prepare后一条命令服务于 SQLx 的离线校验能力开发时用它把query!的查询结果元数据缓存到仓库生成.sqlx目录这样 CI 或未连接数据库的机器上也能通过编译期检查。端到端测试rocket::local 驱动的 CRUD 闭环src/tests.rs 用 Rocket 的本地阻塞客户端rocket::local::blocking::Client对四个挂载点跑同一套测试逻辑验证完整 CRUD 闭环先DELETE清库再GET断言返回空数组循环创建 N20篇文章每次创建后断言列表长度 1且读回的内容与提交的 JSON 一致随后逐个删除DELETE不存在记录时断言返回404三个测试分别针对/sqlx、/diesel、/rusqlite三个路由运行。#[test] fn test_sqlx() { test(/sqlx, crate::sqlx::stage()) }源码注释提醒若多个测试并发派发访问数据库的请求就需要事务或串行化测试——这是多连接池环境下测试隔离的实用经验。小结examples/databases示例的价值在于它在不引入任何外部服务SQLite 部分的前提下把 Rocket 生态中同步/异步 × SQLite/MySQL的数据库接入矩阵完整演示了一遍。无论你偏好rocket_db_pools异步连接池 Connection守卫还是rocket_sync_db_pools同步连接 db.run()包装都可以直接从本示例的stage()/#[database]/迁移 Fairing 三件套中复制出可运行的骨架再替换为自己的表结构与查询逻辑即可。赞分享后端开发工具【免费下载链接】RocketA web framework for Rust.项目地址https://gitcode.com/gh_mirrors/ro/Rocket点击查看免费下载相关推荐GhostTrack 快速上手OSINT 追踪工具实操指南GhostTrack 快速上手OSINT 追踪工具实操指南 你手里只有一个陌生 IP想知道它落在哪个城市。GhostTrack 是台跑在终端里的 OSINT网络安全CLI零基础 5 步完成 JarkViewer 安装配置把新格式图片一次看明白零基础 5 步完成 JarkViewer 安装配置把新格式图片一次看明白 你是不是也遇到过这种尴尬朋友发来一张 HEIC 格式照片双击后系统提示无法打开桌面应用图像处理音视频Rusqlite 实战教程构建完整的 Rust 数据库应用程序Rusqlite 实战教程构建完整的 Rust 数据库应用程序 Rusqlite 是 Rust 语言中一款安全且高性能的 SQLite 数据库库它为 Rus上一篇GLM-5.2核心技术解析IndexShare架构与MTP层优化详解下一篇Laravel Ardent 开源项目教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。