Transactions#

The SQLSpec plugin supports two transaction modes: autocommit and manual commit. Choose the mode that fits your application's error handling and rollback requirements.

Commit Modes#

Autocommit (default)

Each statement commits automatically. Use this for read-heavy workloads or when you don't need atomic multi-statement operations.

Manual Commit

You control when to commit or rollback. Use this for write operations that must succeed or fail together.

commit modes#
from sqlspec import SQLSpec
from sqlspec.adapters.sqlite import SqliteConfig
from sqlspec.extensions.litestar import CommitMode, SQLSpecPlugin

sqlspec = SQLSpec()
sqlspec.add_config(
    SqliteConfig(
        connection_config={"database": ":memory:"},
        extension_config={"litestar": {"commit_mode": CommitMode.autocommit}},
    )
)
sqlspec.add_config(
    SqliteConfig(
        connection_config={"database": ":memory:"},
        extension_config={"litestar": {"commit_mode": CommitMode.manual}},
    ),
    name="manual",
)

plugin = SQLSpecPlugin(sqlspec=sqlspec)

Rollback on Error#

In manual mode, uncaught exceptions trigger an automatic rollback before the response is sent. This keeps your database consistent when handlers fail.

@post("/transfer")
async def transfer(db: AsyncSession, data: TransferRequest) -> dict:
    await db.execute(
        "UPDATE accounts SET balance = balance - :amount WHERE id = :from_id",
        amount=data.amount,
        from_id=data.from_account,
    )
    await db.execute(
        "UPDATE accounts SET balance = balance + :amount WHERE id = :to_id",
        amount=data.amount,
        to_id=data.to_account,
    )
    await db.commit()  # Both updates succeed or both rollback
    return {"status": "transferred"}

Nested Transactions#

Use savepoints for nested transaction scopes. SQLSpec translates begin_nested() to savepoints on databases that support them.