Skip to content

rust.sqlx.missing_transaction

Correctness High

Detects multiple related database operations without transactions.

Missing transactions:

  • Partial updates — Some ops succeed, others fail
  • Data corruption — Inconsistent state
  • Lost data — No rollback on failure
// ❌ Before (no transaction)
async fn transfer_funds(
pool: &PgPool,
from: i64, to: i64, amount: i64
) -> Result<()> {
sqlx::query!("UPDATE accounts SET balance = balance - $1 WHERE id = $2", amount, from)
.execute(pool).await?;
sqlx::query!("UPDATE accounts SET balance = balance + $1 WHERE id = $2", amount, to)
.execute(pool).await?; // If this fails, money vanishes!
Ok(())
}
// ✅ After (with transaction)
async fn transfer_funds(
pool: &PgPool,
from: i64, to: i64, amount: i64
) -> Result<()> {
let mut tx = pool.begin().await?;
sqlx::query!("UPDATE accounts SET balance = balance - $1 WHERE id = $2", amount, from)
.execute(&mut *tx).await?;
sqlx::query!("UPDATE accounts SET balance = balance + $1 WHERE id = $2", amount, to)
.execute(&mut *tx).await?;
tx.commit().await?;
Ok(())
}
  • Multiple INSERT/UPDATE in same function without tx
  • Missing begin()/commit() pairs
  • Money/inventory operations without atomicity

Unfault can wrap operations in a transaction.