python.missing_transaction_boundary
Correctness
High
Detects database operations that span multiple queries without proper transaction boundaries, risking partial updates and data inconsistency.
Why It Matters
Section titled “Why It Matters”Without transaction boundaries:
- Partial updates — Some changes commit while others fail
- Data inconsistency — Database left in invalid state
- Race conditions — Concurrent requests see intermediate states
- Hard to recover — Manual intervention needed to fix data
Example
Section titled “Example”# ❌ Before (no transaction boundary)async def transfer_funds(from_account: str, to_account: str, amount: float): await db.execute( "UPDATE accounts SET balance = balance - ? WHERE id = ?", [amount, from_account] ) # If this fails, money is lost! await db.execute( "UPDATE accounts SET balance = balance + ? WHERE id = ?", [amount, to_account] )# ✅ After (with transaction)async def transfer_funds(from_account: str, to_account: str, amount: float): async with db.transaction(): await db.execute( "UPDATE accounts SET balance = balance - ? WHERE id = ?", [amount, from_account] ) await db.execute( "UPDATE accounts SET balance = balance + ? WHERE id = ?", [amount, to_account] )What Unfault Detects
Section titled “What Unfault Detects”- Multiple database writes without transaction wrapper
- Mixed read/write operations without isolation
- SQLAlchemy sessions without commit/rollback boundaries
- Async database operations without transaction context
Auto-Fix
Section titled “Auto-Fix”Unfault generates patches that wrap operations in transactions:
# SQLAlchemyfrom sqlalchemy.orm import Session
def create_order(session: Session, order_data: dict): with session.begin(): order = Order(**order_data) session.add(order) for item in order_data['items']: session.add(OrderItem(order=order, **item))SQLAlchemy Patterns
Section titled “SQLAlchemy Patterns”# Recommended: Use session context managerfrom sqlalchemy.orm import sessionmaker
Session = sessionmaker(bind=engine)
def process_data(): with Session() as session: with session.begin(): # All operations here are in one transaction pass # Auto-commit on success, rollback on exception