Una importación extensa puede fallar por una conexión interrumpida, un dato inválido o un límite de tiempo del proceso. Si todos los cambios dependen de una sola transacción, el sistema puede mantener bloqueos durante demasiado tiempo y perder todo el trabajo confirmado solo al final. Si, en cambio, cada fila se guarda de forma independiente sin un plan de recuperación, una interrupción puede dejar datos incoherentes.
Diseñar transacciones por lote en importaciones PHP consiste en escoger unidades de trabajo que puedan confirmarse, registrarse y repetirse de forma segura. No equivale a hacer que toda la importación sea atómica: normalmente, cada lote es atómico por separado y el proceso completo puede quedar parcialmente aplicado. Esa distinción debe reflejarse tanto en la implementación como en la experiencia operativa.
Por qué una transacción única puede ser inadecuada

Una transacción larga puede retener bloqueos, aumentar la presión sobre el registro de transacciones y competir con las consultas de la aplicación. Si la importación procesa millones de filas, también es difícil saber cuánto falta y qué hacer después de un fallo. El comportamiento exacto depende del motor de base de datos, el nivel de aislamiento y el volumen de escrituras, por lo que conviene medirlo en el entorno real.
Confirmar cada fila reduce la duración de cada transacción, pero puede multiplicar el coste de las confirmaciones y dejar dependencias entre filas a medio aplicar. El lote ofrece un punto intermedio: si una operación del grupo falla y la excepción se propaga, se revierte ese grupo; los lotes anteriores ya confirmados permanecen. La aplicación debe comunicarlo como progreso parcial, no como un éxito global ni como un rollback total.
Elegir el límite transaccional adecuado
La unidad no tiene por qué ser siempre un número fijo de filas. Debe representar cambios que puedan validarse y persistirse de manera coherente. Si cada registro es independiente, un lote de filas puede ser suficiente. Si varios registros forman una entidad de negocio —por ejemplo, una cabecera y sus líneas—, mantener ese conjunto en la misma transacción evita guardar una entidad incompleta.
Para seleccionar el tamaño, evalúa la duración de cada lote, el volumen de memoria, la contención sobre tablas compartidas, la frecuencia de errores y el coste de repetir trabajo. Un lote grande reduce el número de confirmaciones, pero tarda más en procesarse y amplía el trabajo que hay que rehacer ante un fallo. Uno pequeño limita ese coste, aunque aumenta la sobrecarga y puede perjudicar el rendimiento. No hay un tamaño universal: empieza con un valor configurable y ajústalo con pruebas de carga representativas.
En PHP, evita acumular el fichero completo en memoria si puede recorrerse de manera incremental. Lee un grupo acotado de filas, valida sus campos, inicia la transacción, aplica las escrituras y confirma. Si ocurre un error, revierte la transacción del lote y clasifica el fallo. Con PDO, por ejemplo, el control puede expresarse con beginTransaction(), commit() y rollBack(); el tratamiento de excepciones debe asegurar que no se intente confirmar una transacción fallida.
Registrar el avance para reanudar de forma fiable
Un checkpoint indica qué parte del origen se procesó de forma confirmada. Puede ser un identificador estable, una posición en un fichero o una clave compuesta, siempre que permita continuar sin depender de un orden cambiante. En una consulta paginada, suele ser más seguro avanzar por una clave estable que usar un desplazamiento que pueda cambiar si se insertan o eliminan registros durante el proceso.
El progreso y los cambios del lote deben quedar coordinados. Cuando sea viable, guarda en la misma transacción las escrituras de negocio y el nuevo checkpoint. Así, si el proceso cae antes de confirmar, no queda registrado un avance que la base de datos no aplicó; si confirma, el cursor también avanza. Si el estado de ejecución reside en otro sistema, no existe esa atomicidad automática: hay que diseñar una reconciliación o aceptar que se repetirán lotes y hacerlos idempotentes.
Guarda además el identificador de la importación, su estado, el checkpoint, los contadores y, cuando proceda, una referencia a la versión o huella del fichero. Al reanudar, verifica que se trata de la misma entrada y de una ejecución recuperable. Define estados explícitos, como pendiente, en curso, completada y fallida, y una política para detectar ejecuciones abandonadas. Evita marcar como completada una importación solo porque el proceso terminó sin lanzar una excepción: comprueba que se alcanzó el final esperado.
Aislar errores y controlar los reintentos
Decide de antemano si un registro inválido debe detener todo, excluirse o marcarse para revisión. Para errores de formato previsibles, puede ser útil validar antes de abrir la transacción y registrar el motivo junto con un identificador de fila. Para errores de persistencia, revierte el lote afectado. Continuar con los lotes siguientes solo es razonable si sus datos son independientes y la importación puede declararse parcial con claridad.
Distingue errores permanentes —como un valor obligatorio ausente— de fallos transitorios —como una interrupción recuperable de conexión—. Reintentar un error permanente desperdicia recursos y dificulta el diagnóstico. En cambio, un reintento transitorio puede usar un número limitado de intentos y una espera creciente. Si se agotan, conserva el estado y el contexto suficientes para investigar y reanudar sin ocultar la causa original.
Los reintentos pueden repetir escrituras si no se diseñan con cuidado. Usa claves de negocio o identificadores de origen para reconocer registros ya importados, y decide si una repetición debe insertar, actualizar, ignorar o señalar un conflicto. Las restricciones únicas en la base de datos pueden reforzar esa decisión, pero no sustituyen la lógica de negocio. Evita que el checkpoint sea el único mecanismo contra duplicados: puede quedar desfasado o no cubrir cambios realizados por otra vía.
Si un lote también envía correos, publica mensajes o llama a una API, la transacción de la base de datos no puede deshacer esos efectos externos. No los ejecutes como si fueran parte de una transacción distribuida inexistente. Una alternativa es registrar el evento pendiente en una tabla de salida transaccional y procesarlo después con reintentos e identificadores idempotentes. Si el efecto externo falla, el estado debe permitir recuperarlo sin duplicar la operación ni afirmar que el lote está completamente terminado.
Probar consistencia, avance y recuperación
Las pruebas deben cubrir algo más que la ruta correcta. Inyecta fallos antes de iniciar una transacción, durante las escrituras, justo antes de confirmar y después de confirmar pero antes de actualizar cualquier estado externo. Verifica qué datos permanecen, qué checkpoint se conserva y si una reanudación produce el resultado esperado. Incluye registros duplicados, filas inválidas, lotes vacíos y errores de persistencia.
En una prueba representativa, mide duración por lote, memoria, tasa de errores, tiempo de bloqueo y progreso. Comprueba también que los contadores distinguen filas leídas, aceptadas, rechazadas y confirmadas; «procesadas» puede ser ambiguo si incluye cambios revertidos. Las métricas y los registros deberían identificar la importación y el lote, sin volcar datos sensibles que no sean necesarios para diagnosticar.
Lista de comprobación antes de producción

- La unidad transaccional coincide con una unidad coherente de negocio.
- El tamaño del lote es configurable y se ha evaluado con datos y carga representativos.
- El checkpoint avanza solo cuando el lote correspondiente está confirmado.
- La estrategia de reanudación usa una clave estable y reconoce la entrada de origen.
- Los errores permanentes y transitorios tienen tratamientos distintos y observables.
- Las operaciones repetidas son idempotentes o detectan conflictos de forma explícita.
- Los efectos externos se procesan con una estrategia independiente y recuperable.
- Las pruebas verifican fallos en distintos puntos, no solo la ejecución completa.
El objetivo no es impedir cualquier fallo, sino limitar sus consecuencias y hacer explícito el estado resultante. Con límites transaccionales razonados, checkpoints coherentes y reintentos seguros, una importación PHP puede recuperarse sin confundir avance parcial con finalización ni volver a aplicar cambios ya confirmados.



