域名 AXUM.RS 将于2025年10月到期。我们无意再对其进行续费,我们希望你能够接续这个域名,让更多 AXUM 开发者继续受益。
  • 方案1️⃣AXUM.RS 域名 = 3000
  • 方案2️⃣方案1️⃣ + 本站所有专题原始 Markdown 文档 = 5000
  • 方案3️⃣方案2️⃣ + 本站原始数据库 = 5500
如果你有意接续这份 AXUM 情怀,请与我们取得联系。
说明:
  1. 如果有人购买 AXUM.RS 域名(方案1️⃣),或者该域名到期,本站将启用新的免费域名继续提供服务。
  2. 如果有人购买了 AXUM.RS 域名,且同时购买了内容和/或数据库(方案2️⃣/方案3️⃣),本站将关闭。届时我们或许会以另一种方式与你再相遇。

sqlx概览

开始之前,我们需要一些准备工作,包括:创建用于演示的数据库及数据、创建一个 Rust 项目以及为项目编写一些基础性代码。

示例数据库及数据

本专题我们使用 MySQL 8 数据库,并只使用一张会员(memeber)表:

你可以在filess.io里创建一个免费的 MySQL 8 实例

字段名说明
id自动编号
name会员名称
dateline会员加入时间
balance账户余额
types会员类型。在 Rust 中使用枚举,而 MySQL 中使用 TINYINT。你将看到如何为这两者建立映射。
is_del是否删除

表结构如下:

CREATE TABLE member (
    id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(30) NOT NULL COMMENT '会员名称',
    dateline DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '加入时间',
    balance INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '账户余额',
    types TINYINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '会员类型',
    is_del BOOLEAN NOT NULL DEFAULT FALSE COMMENT '是否删除',
    UNIQUE(name)
) ENGINE=INNODB CHARSET=UTF8MB4 COLLATE=utf8mb4_unicode_ci;

创建项目及依赖

使用 cargo 创建名为 axum-sqlx 的项目:

cargo new axum-sqlx

并加上依赖:

[dependencies]
tokio = {version="1",features=["full"]}
axum = "0.6"
serde = {version="1", features=["derive"]}
chrono = {version="0.4", features=["serde"]}
sqlx = { version = "0.6", features = [ "runtime-tokio-native-tls", "mysql","chrono", "macros" ] }
dotenv = "0.15"
config = "0.13"
tracing = "0.1"
tracing-subscriber = "0.3"

这里对 sqlxfeatures 进行简要说明:

  • runtime-tokio-native-tls:使用 tokio 运行时,以及使用原生的 tls,在 debian/ubuntu 中,通常由 libssl-dev 提供。
  • mysql:MySQL 数据库
  • chrono:支持将 chronon 映射到 MySQL 时间相关的数据类型
  • macros:开启 query! 等宏的支持

基础性代码

基础性代码无非就是配置文件 、错误处理、状态共享、日志等,在和其它专题的相差不大,这里不再重复。我们重点看一下数据模型的定义:

枚举 MemberTypes

#[derive(Debug, Default, Deserialize, Serialize, sqlx::Type, Clone)]
#[repr(u8)]
pub enum MemberTypes {
    #[default]
    /// 普通会员
    Normal,
    /// 白银会员
    Silver,
    /// 黄金会员
    Gold,
    /// 钻石会员
    Diamond,
}
  • #[derive(sqlx::Type)]:用于将这个枚举声明为 sqlx 的类型
  • #[repr(u8)]:将枚举值的类型替换为 u8

有了以上两步,MemberTypes 就能成功通过 sqlx 映射为数据库的 TINYINT UNSIGNED 类型了。

想一想:PostgreSQL 并没有 UNSIGNED,所以它只能映射为 i8,因此例中的 #[repr(u8)] 应该改为 #[repr(i8)]

想一想:PostgreSQL 并没有 UNSIGNED,所以它只能映射为 i8,因此例中的 #[repr(u8)] 应该改为 #[repr(i8)]

结构体 Member

#[derive(Debug, Default, Deserialize, Serialize, sqlx::FromRow)]
pub struct Member {
    pub id: u32,
    pub name: String,
    pub dateline: chrono::DateTime<chrono::Local>,
    pub balance: u32,
    pub types: MemberTypes,
    pub is_del: bool,
}
  • #[derive(sqlx::FromRow)]:使 sqlx 具有自动将查询结果映射到结构体的功能(比如 query_as()
  • pub dateline: chrono::DateTime<chrono::Local>:将数据库中的 DATETIME 类型映射到 rust 中的 chrono::DateTime<chrono::Local>类型
  • pub types: MemberTypes:将数据库中的 TINYINT UNSIGNED 映射到 rust 中的枚举

想一想:和 MySQL 的 DATETIME 类似,PostgreSQL 中的 TIMESTAMPTZ 也可以映射到 chrono::DateTime<T>

想一想:和 MySQL 的 DATETIME 类似,PostgreSQL 中的 TIMESTAMPTZ 也可以映射到 chrono::DateTime<T>

本章代码位于01/准备工作分支。

要查看完整内容,请先登录