rust.sqlx.missing_transaction
Correctness
High
Detects multiple related database operations without transactions.
Why It Matters
Section titled “Why It Matters”Missing transactions:
- Partial updates — Some ops succeed, others fail
- Data corruption — Inconsistent state
- Lost data — No rollback on failure
Example
Section titled “Example”// ❌ 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(())}What Unfault Detects
Section titled “What Unfault Detects”- Multiple INSERT/UPDATE in same function without tx
- Missing begin()/commit() pairs
- Money/inventory operations without atomicity
Auto-Fix
Section titled “Auto-Fix”Unfault can wrap operations in a transaction.