SQLx 中的 `&mut *transaction` 和 `&mut transaction` 有什么区别?

问题描述 投票:0回答:2

我很好奇在我的示例中

&mut *transaction
&mut transaction
之间有什么区别,因为我不认为
transaction
是一个开始的指针,但由于某种原因
&mut *transaction
满足特征约束,而
&mut transaction 
没有。

这是我的工作代码:

use sqlx::{PgPool, Transaction, Executor};
use chrono::{DateTime, Utc};

pub struct SimpleDbClient {
    db: PgPool,
}

pub trait AddCharacterEntries {
    async fn insert_character_entries(&self, timestamp: DateTime<Utc>, char_values: Vec<(char, i32)>) -> sqlx::Result<()>;
}

impl AddCharacterEntries for SimpleDbClient {
    async fn insert_character_entries(&self, timestamp: DateTime<Utc>, char_values: Vec<(char, i32)>) -> sqlx::Result<()> {
        let mut transaction = self.db.begin().await?;
        for (character, ascii_value) in char_values {
            sqlx::query!(
                r#"
                INSERT INTO character_log (timestamp, character, ascii_value)
                VALUES ($1, $2, $3)
                "#,
                timestamp,
                character as char,
                ascii_value
            )
            .execute(&mut *transaction)
            .await?;
        }
        transaction.commit().await?;
        Ok(())
    }
}

如果我将上面的内容更改为

.execute(&mut transaction)
,我会收到此错误:

rustc: the trait bound `&mut sqlx::Transaction<'_, sqlx::Postgres>: sqlx::Executor<'_>` is not satisfied
the following other types implement trait `sqlx::Executor<'c>`:
  <&'c mut sqlx::PgConnection as sqlx::Executor<'c>>
  <&'c mut sqlx::sqlx_postgres::PgListener as sqlx::Executor<'c>>
  <&'c mut sqlx::AnyConnection as sqlx::Executor<'c>>
  <&sqlx::Pool<DB> as sqlx::Executor<'p>> [E0277]
rustc: required by a bound introduced by this call [E0277]

这是否归结为进行某种类型转换?很好奇这是否会被视为一种限制,或者编译器认为这两个表达式是不同的对象实际上是否有意义。

rust traits rust-sqlx
2个回答
5
投票

我不认为

transaction
是一个开始的指针

您缺少的是

Transaction
实现
Deref
DerefMut
。当您尝试对实现
Deref
的值调用方法时,Rust 可以通过这些特征自动取消引用,但您也可以使用
*
运算符显式取消引用。然后
&mut
获取对此值的引用,在本例中是
PgConnection

  • transaction
    是类型
    Transaction<Postgres>
  • *transaction
    是类型
    PgConnection
  • &mut *transaction
    是类型
    &mut PgConnection

因为 sqlx 实现了这些特征,所以这允许您透明地在

Transaction
值上调用底层数据库连接的任何(非消耗)方法,类似于透明地执行切片类型的任何(非消耗)方法在
Vec

请注意,在使用实现

&*
(也可能是
&mut *
)的类型时,重借(
Deref
DerefMut
)是常见模式。一些例子:

  • 鉴于
    some_vec
    Vec<T>
    &*some_vec
    会给你一个
    &[T]
  • 鉴于
    some_box
    Box<T>
    &*some_box
    会给你一个
    &T

4
投票

这里有几个活动部件。您没有指定您正在使用的

sqlx
版本,但从您收到的错误来看,我认为这是
0.7.x
,因此我的答案将针对此版本。

Query::execute
Executor
作为参数。请注意
Executor
文档中的以下部分:

针对以下情况实施:

  • &泳池
  • &mut 连接

Executor
Transaction
PoolConnection
隐含已被删除,因为如果不完全重写
Executor
特性,它们就无法存在于新的 crate 架构中。要修复此损坏,只需在需要
impl Executor
的位置添加取消引用,因为它们都取消引用仍将实现它的内部连接类型:

  • &mut transaction
    ->
    &mut *transaction
  • &mut connection
    ->
    &mut *connection

由于

Transaction
实现了
Deref<Target = <DB as Database>::Connection>
,你必须取消引用并重新借用它(即创建
&mut *transaction
),将其传递给
execute

© www.soinside.com 2019 - 2024. All rights reserved.