域名 AXUM.RS 将于 2025 年 10 月到期。我们无意再对其进行续费,如果你有意接续这个域名,请与我们取得联系。
  • AXUM.RS 现仅需人民币 3000 元(大写:叁仟元整。接受适度议价
  • 按照行业规则,AXUM.RS 到期后,大概率会进入长时间的赎回期,该期间内,如果你想拥有该域名,将要付出高额的费用
  • 我们已启用 AXUM.EU.ORG 域名,并将持续运营
  • 仅接受微信或支付宝交易
如果你对 AXUM.RS 有兴趣,请和我们进行联系:

使用sqlx的事务实现转账

本章我们将通过用户之间转账来讨论 sqlx 的事务。为了保证转账的完整性、正确性,我们必须使用事务来处理。

事务的常用操作

  • 开启事务:conn.begin().await
  • 提交事务:tx.commit().await
  • 回滚事务:tx.rollback().await

开启事务

let mut tx = conn.begin().await.map_err(Error::from)?;
  • 事务必须由 mut 修饰
  • &sqlx::MySqlPoolbegin() 方法可以开启一个事务

转出账户扣款

let from_aff =
    match sqlx::query("UPDATE member SET balance=balance-? WHERE name=? AND balance>=?")
        .bind(&t.amount)
        .bind(&t.from_member)
        .bind(&t.amount)
        .execute(&mut tx)
        .await
    {
        Ok(r) => r.rows_affected(),
        Err(err) => {
            tx.rollback().await.map_err(Error::from)?;
            return Err(Error::from(err));
        }
    };

if from_aff < 1 {
    tx.rollback().await.map_err(Error::from)?;
    return Err(Error::tran("转账失败,请检查转出账户是否有足够余额"));
}
  • 为了确保转出账户有足够的余额,我们的 SQL 语句的 WHERE 条件是:name=? AND balance>=?,即转出账户的名称等于传入的名称、账户余额大于等于转账金额
  • 通过 match 来处理不同的情况
    • 成功时,返回受影响的行数
    • 失败时,回滚事务,并返回错误
  • 注意,execute()的参数不再是 conn ,而是 &mut tx,即事务:execute(&mut tx)
  • if from_aff < 1 :如果受影响的行数小于1,说明扣款失败,这时应该回滚事务。扣款失败可能的原因有:
    • 账户余额不足
    • 输入的会员名称不存在
  • 成功时,返回受影响的行数
  • 失败时,回滚事务,并返回错误
  • 账户余额不足
  • 输入的会员名称不存在

增加转入账户的余额

let to_aff = match sqlx::query("UPDATE member SET balance=balance+? WHERE name=?")
    .bind(&t.amount)
    .bind(&t.to_member)
    .execute(&mut tx)
    .await
{
    Ok(r) => r.rows_affected(),
    Err(err) => {
        tx.rollback().await.map_err(Error::from)?;
        return Err(Error::from(err));
    }
};
tx.commit().await.map_err(Error::from)?;

只有提交了事务,修改的数据才会真实提交到数据库里。

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