You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将sqlx::Executor传递给嵌套Future?

解决PgExecutor多次传递时的移动语义问题(兼容PgPool与PgTransaction)

核心问题是PgExecutor的所有权转移导致二次调用失败:当你把db作为值传递给inner函数时,所有权会被转移,后续无法再使用原变量;而PgConnection(事务解引用后的底层类型)不实现Clone,没法直接复制一份来规避这个问题。

以下是两种简洁的解决方案:

方案1:传递PgExecutor的引用给inner函数

修改inner函数的参数为引用类型,这样不会转移所有权,outer中的db可以被多次复用,同时兼容PgPool和PgTransaction场景:

use sqlx::{PgExecutor, PgPool};

#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
    let pool = PgPool::connect("postgres:///").await?;

    let mut tx = pool.begin().await?;
    outer(&mut *tx).await?;
    tx.commit().await
}

async fn outer(db: impl PgExecutor<'_>) -> sqlx::Result<()> {
    // 传递db的引用,不转移所有权
    dbg!(inner(&db, "first").await?);
    dbg!(inner(&db, "second").await?);

    Ok(())
}

async fn inner(db: &impl PgExecutor<'_>, name: &str) -> sqlx::Result<String> {
    sqlx::query_scalar!(r#"SELECT $1 as "name!""#, name)
        .fetch_one(db)
        .await
}

原理说明

sqlx的fetch_one等查询方法支持接受引用类型的Executor,&PgPool、&mut PgTransaction都实现了PgExecutor trait,因此传递引用完全符合查询要求,同时避免了所有权转移的问题。

方案2:将outer的参数改为引用类型(可选)

如果业务场景允许,也可以直接让outer函数接受引用类型,内部传递时更直观:

async fn outer(db: &impl PgExecutor<'_>) -> sqlx::Result<()> {
    dbg!(inner(db, "first").await?);
    dbg!(inner(db, "second").await?);

    Ok(())
}

async fn inner(db: &impl PgExecutor<'_>, name: &str) -> sqlx::Result<String> {
    sqlx::query_scalar!(r#"SELECT $1 as "name!""#, name)
        .fetch_one(db)
        .await
}

这种方式和方案1本质一致,只是把引用的层级提前到了outer的参数上,可根据代码结构选择使用。

内容的提问来源于stack exchange,提问作者imbolc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 05:12:46