Skip to main content

Transaction

Struct Transaction 

Source
pub struct Transaction<'p, DB> { /* private fields */ }
Expand description

Transaction builder for composing multi-entity operations.

Use Transaction::new to create a builder, chain .with_*() methods to declare which entities you’ll use, then call .run() to execute.

§Type Parameters

  • 'p — Pool lifetime
  • DB — Database pool type (e.g., PgPool)

§Example

Transaction::new(&pool)
    .run(async |ctx| {
        let user = ctx.users().find_by_id(id).await?;
        ctx.orders().create(order).await?;
        Ok(())
    })
    .await?;

Implementations§

Source§

impl<'p, DB> Transaction<'p, DB>

Source

pub const fn new(pool: &'p DB) -> Self

Create a new transaction builder.

§Arguments
  • pool — Database connection pool
§Example
let tx = Transaction::new(&pool);
Source

pub const fn pool(&self) -> &'p DB

Get reference to the underlying pool.

Source§

impl Transaction<'_, PgPool>

Source

pub async fn run<F, T, E>(self, f: F) -> Result<T, E>
where F: AsyncFnOnce(&mut TransactionContext) -> Result<T, E>, E: From<Error> + Debug,

Execute a closure within a PostgreSQL transaction.

Commits the transaction explicitly when the closure returns Ok. On Err, the transaction context is dropped and sqlx rolls back automatically via its Drop implementation.

The closure receives &mut TransactionContext (not by value) so that run retains ownership and can invoke commit().await on success.

§Type Parameters
  • F — Async closure
  • T — Success type
  • E — Error type (must be convertible from sqlx::Error)
§Example
Transaction::new(&pool)
    .run(async |ctx| {
        let user = ctx.users().create(dto).await?;
        Ok(user)
    })
    .await?;
§Errors

Propagates any error from the closure, from begin, or from commit.

Source

pub async fn run_with_commit<F, Fut, T, E>(self, f: F) -> Result<T, E>
where F: FnOnce(TransactionContext) -> Fut + Send, Fut: Future<Output = Result<T, E>> + Send, E: From<Error> + Debug,

Execute a closure within a transaction with explicit commit.

§⚠️ The closure MUST call ctx.commit().await on every successful path

run_with_commit hands ownership of TransactionContext to the closure. There is no type-level guarantee that the closure commits; if it returns Ok(...) without calling commit, ctx is dropped and the underlying sqlx::Transaction::Drop silently rolls back. The caller observes Ok and assumes the writes persisted — they did not. This is the same failure mode that affected the old run() implementation; here it is preserved on purpose so callers can implement conditional commit logic, at the cost of moving the responsibility onto the closure.

Prefer run unless you genuinely need to decide commit-or-rollback inside the closure. run performs the commit automatically on Ok and rolls back on Err, eliminating this footgun.

§Examples

Correct — closure commits on the success path:

Transaction::new(&pool)
    .run_with_commit(|mut ctx| async move {
        let user = ctx.users().create(dto).await?;
        ctx.commit().await?;     // <-- required
        Ok(user)
    })
    .await?;

Wrong — closure returns Ok without committing; the write is rolled back when ctx drops, but the caller sees Ok(user):

Transaction::new(&pool)
    .run_with_commit(|mut ctx| async move {
        let user = ctx.users().create(dto).await?;
        // BUG: forgot `ctx.commit().await?` — the row is rolled back.
        Ok(user)
    })
    .await?;

Conditional commit — the intended use case:

Transaction::new(&pool)
    .run_with_commit(|mut ctx| async move {
        let user = ctx.users().create(dto).await?;
        if user.flagged {
            ctx.rollback().await?;
            return Ok(None);
        }
        ctx.commit().await?;
        Ok(Some(user))
    })
    .await?;
§Errors

Propagates any error from the closure or database transaction.

Auto Trait Implementations§

§

impl<'p, DB> Freeze for Transaction<'p, DB>

§

impl<'p, DB> RefUnwindSafe for Transaction<'p, DB>
where DB: RefUnwindSafe,

§

impl<'p, DB> Send for Transaction<'p, DB>
where DB: Sync,

§

impl<'p, DB> Sync for Transaction<'p, DB>
where DB: Sync,

§

impl<'p, DB> Unpin for Transaction<'p, DB>

§

impl<'p, DB> UnsafeUnpin for Transaction<'p, DB>

§

impl<'p, DB> UnwindSafe for Transaction<'p, DB>
where DB: RefUnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more