域名 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实现增删改

本章将讨论使用 sqlx 进行增删改(INSERT/DELETE/UPDATE)操作。

判断是否存在

开始之前,我们需要定义一个函数,用于判断增加或修改的会员是否存在。在数据库中,我们将 name 字段定义成了 unique,所以只需要判断是否存在相同 name 的记录就行了。

原理很简单,就是通过 SELECT COUNT(*) 来统计指定 name 的记录数,如果这个记录大于0,说明该会员已经存在。

这里有个很奇怪的 id: Option<u32>,它是做什么用的?

  • 对于增加记录来说,只要判断是否存在指定 name的记录就行了
  • 对于修改记录来说,除了要判断是否存在指定 name 的记录,还要判断这个记录是否是它自己。如果不加这个条件,即使不做任何数据的修改,都无法进行操作,exists() 永远返回 true

增加

// src/db/member.rs

pub async fn add(conn: &sqlx::MySqlPool, m: &model::member::Member) -> Result<u32> {
    if exists(conn, &m.name, None).await? {
        return Err(Error::exists("同名的会员已存在"));
    }

    let id = sqlx::query(
        "INSERT INTO `member` (name, dateline, balance, types,is_del) VALUES(?,?,?,?,?)",
    )
    .bind(&m.name)
    .bind(&m.dateline)
    .bind(&m.balance)
    .bind(&m.types)
    .bind(&m.is_del)
    .execute(conn)
    .await
    .map_err(Error::from)?
    .last_insert_id();

    Ok(id as u32)
}

结合 query()execute(),我们执行了 INSERT 语句,并返回了它最后插入的ID。为什么返回的时候要转成 u32Ok(id as u32))呢?

  • 为了兼容 BIGINT UNSIGNEDlast_insert_id() 返回的是 u64
  • 虽然你可以直接使用 u64 ,但我们的表的主键是 INT UNSIGNED,对应的是 u32。为了统一性,我们还是将它转成了 u32

修改

// src/db/member.rs

pub async fn edit(conn: &sqlx::MySqlPool, m: &model::member::Member) -> Result<u64> {
    if exists(conn, &m.name, Some(m.id)).await? {
        return Err(Error::exists("同名的会员已存在"));
    }

    let aff = sqlx::query("UPDATE `member` SET name=?,balance=?,types=? WHERE id=?")
        .bind(&m.name)
        .bind(&m.balance)
        .bind(&m.types)
        .bind(&m.id)
        .execute(conn)
        .await
        .map_err(Error::from)?
        .rows_affected();

    Ok(aff)
}

结合 query()execute(),我们执行了 UPDATE 语句,并返回了受影响的行数。和 INSERT 返回的最后插入ID不同,受影响行数无须转成 u32

逻辑删除说到底就是将 is_del 字段的值改成 true,它就是一个 UPDATE 操作。

物理删除

// src/db/member.rs

pub async fn real_del(conn: &sqlx::MySqlPool, id: u32) -> Result<u64> {
    let aff = sqlx::query("DELETE FROM member WHERE id=?")
        .bind(id)
        .execute(conn)
        .await
        .map_err(Error::from)?
        .rows_affected();
    Ok(aff)
}

本章代码位于04/增删改分支

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