Las transacciones en SQLAlchemy tratan varios cambios como una unidad: todos se confirman con commit o todos se deshacen con rollback. La Session sigue los objetos ORM, implementa el patrón unit of work y obtiene una conexión cuando necesita comunicarse con la base.

Consulta primero la guía completa de SQLAlchemy si los mapeos y consultas son nuevos para ti. La decisión central consiste en definir el límite de la transacción y no vincular la Session a toda la vida de la aplicación.

Delimita la transacción con context managers

from sqlalchemy import create_engine
from sqlalchemy.orm import Session

engine = create_engine("postgresql+psycopg://app:clave@localhost/app")

def transferir(origen, destino, importe):
    with Session(engine) as session:
        with session.begin():
            origen.saldo -= importe
            destino.saldo += importe
            session.add_all([origen, destino])

Si el bloque termina normalmente, session.begin() confirma. Si aparece una excepción, revierte y propaga el error. El bloque exterior cierra la Session y libera recursos. No captures una excepción solo para ocultarla, porque el llamador debe saber que la transferencia falló.

from sqlalchemy.orm import sessionmaker

SessionLocal = sessionmaker(bind=engine)

with SessionLocal.begin() as session:
    session.add(nuevo_pedido)

flush no es commit

flush() envía los INSERT, UPDATE y DELETE pendientes sin cerrar la transacción. Sirve para obtener una clave generada antes de crear otro objeto:

with SessionLocal.begin() as session:
    pedido = Pedido(cliente_id=42)
    session.add(pedido)
    session.flush()
    session.add(Item(pedido_id=pedido.id, sku="PY-01"))

Una consulta o commit() puede provocar un flush automático. Si falla una restricción, la Session queda inactiva para esa transacción. Ejecuta rollback() o deja que el context manager lo haga antes de continuar.

Alcance de Session en aplicaciones web

Es habitual abrir una Session por petición, ejecutar la lógica, confirmar escrituras y cerrarla al final. No compartas una instancia entre hilos o tareas asíncronas. Para código async, crea una AsyncSession por tarea y consulta la guía de SQLAlchemy asíncrono.

Evita llamar a commit() dentro de cada función del repositorio. Eso impide que una operación de negocio con varios pasos sea atómica. La capa que conoce la unidad de trabajo completa debe decidir cuándo confirmar.

Recupera una etapa con savepoint

with SessionLocal.begin() as session:
    session.add(lote)
    try:
        with session.begin_nested():
            session.add(item_opcional)
            session.flush()
    except IntegrityError:
        registrar_item_rechazado()

begin_nested() crea un savepoint. El error lo revierte sin descartar necesariamente la transacción exterior. Úsalo con intención; no sustituye unos límites de transacción bien diseñados.

Pruebas y errores frecuentes

Prueba el éxito y un fallo a mitad de la operación, comprobando que no quede estado parcial. Evita Sessions globales, transacciones abiertas durante llamadas HTTP lentas y excepciones genéricas que oculten fallos. Mantén la transacción corta, pero suficiente para representar una regla de negocio indivisible.

La documentación oficial de transacciones de SQLAlchemy, consultada el 28 de julio de 2026, explica autobegin, context managers, savepoints y niveles de aislamiento.