Migración a script iterativo de carga de datos y implementación de bloqueo por intentos fallidos de login

Fecha: 1 de mayo 2026

Hora de inicio: 2:00 p.m. 

Hora de finalización: 9:00 p.m.

Horas trabajadas: 3h 40 min

Después de tener el SP CargarDatos funcionando, se envió una consulta al profesor sobre si este SP era aceptable, dado que en la clase del miércoles él mencionó algo que no había tenido en cuenta relacionado con como se leían los movimientos. El profesor indicó que los movimientos debían procesarse de forma iterativa, o sea, cada movimiento con su propia transacción atómica para garantizar consistencia, cosa que no se había hechi. Esto llevó a una migración completa del SP a un script SQL puro con tablas variables y un WHILE loop. Simultáneamente, se implementó la funcionalidad de bloqueo de login después de 5 intentos fallidos en 20 minutos.

Actividades realizadas

2:00 p.m. - 4:30 p.m.
Durante este lapso se le hicieron varias consultas al profesor relacionadas con la antigua forma planteada para cargar los datos.

    Img 1: conversación con el profesor mediante whatsApp

Después de la conversación llegamos a la conclusión de que lo mejor era hacer un nuevo script (ampliamente basado en el SP original) pero cambiando la forma de procesar los movimeintos.


5:30 p.m. - 7:00 p.m.

El script comienza insertando los catálogos (Puestos, TipoEvento, TipoMovimiento, Usuarios, Error) de forma masiva desde el XML usando INSERT INTO ... SELECT ... FROM @xml.nodes(). Estos inserts no requieren lógica especial. Esta parte fue práctimcamente un copypage del SP original

Para los movimientos, el enfoque cambió drásticamente. En lugar de procesar todo en una única transacción grande, se usa una tabla variable @movimientos que actúa como "cola" de movimientos a procesar:



                                    Img 2: Tabla variable

El RowNum IDENTITY permite iterar sobre la tabla. Los movimientos se ordenan por fecha ascendente para simular el procesamiento cronológico del sistema.

Luego, un while procesa cada movimiento uno por uno:

                                   Img 3: Fragmento del while

Cada movimiento tiene su propia transacción: INSERT + UPDATE saldo juntos. Si una falla, solo se revierte ese movimiento. Como cada movimiento actualiza el saldo del empleado, el siguiente movimiento ve el saldo correcto, no necesita subconsultas complejas para calcular saldos acumulados, a diferencia del SP original.

Un tiempo después de haber terminado el Script, le consulté al profesor si ahora sí estaba bien la manera en la que planteamos el procesamiento de los movimientos y me dijo que sí.

7:20 p.m. - 8: 30 p.m.

Bloqueo por intentos fallidos de login

Se creó un nuevo SP VerificarBloqueo que se llama en el GET del login:

    Img 4: método verifar_bloqueo


En el controlador, el GET pasa el username como query parameter para que VerificarBloqueo pueda verificar si ese usuario específico está bloqueado:

    Img 5: fragmento del GET en el controlador

Y en el login se deshabilita el botón de iniciar sesión si bloqueado == 1.

Errores encontrados

Error 1 : Conteo incorrecto de intentos fallidos en Login

El bloqueo nunca se activaba porque el conteo de intentos buscaba por IdUsuario, pero cuando el password era incorrecto se registraba con el id real del usuario. Sin embargo, cuando el username no existía, se registraba con IdUsuario = 0. El conteo siempre daba 0 para usuarios sin intentos previos.

Solución: Modificar el SP para buscar intentos donde IdUsuario = id_real OR IdUsuario = 0 (usuario desconocido).

Error 2: Caracteres especiales en el XML

La ñ y tildes causaban errores al pasar el XML como string. Solución: Prefijo N'...' en el script para indicar que es Unicode.

Error 3 :Botón no se veía deshabilitado

El atributo disabled estaba pero el CSS lo sobreescribía. Solución: Agregar .btn-accion:disabled { opacity: 0.5; cursor: not-allowed; } en estilos.css.


Pruebas Básicas

Dado que las pruebas anteriores las había hecho con el SP original, quería asegurarme de que el nuevo script funcionara correctamente, así que hice una serie de pruebas, en las siguientes páginas habrá una serie de fotos que corresponden a las pruebas que realicé:



Saldos correctos:

Ver que la bitácora de eventos sí se llene:



Buenas prácticas descubiertas

  • Tabla variable + WHILE en lugar de cursor: permite lógica clara y el profe lo permite (a diferencia del cursor), y es más sencillo que realizar las subconsultas correladiconadas.
  • Transacción atómica por movimiento: arantiza que INSERT + UPDATE van juntos o no van.
  • Movimientos ordenados por fecha: simula el flujo cronológico real, simplificando cálculos de saldo.
  • Username en URL como query parameter: permite verificar bloqueo del usuario correcto al recargar la página.

Referencias:

  • Curso de SQL Server 2021 desde cero | T-SQL, VARIABLES TIPO TABLA (video 58): https://youtu.be/Z8__Yt6v6mw?si=ptATP6VnjjdbrVGU

  • Curso de SQL Server 2021 desde cero | T-SQL, VARIABLES (video 57): https://youtu.be/k5_2r2nLXzo?si=J0E9dytG76QWSGwV

  • SP de cargar datos previamente creado

  • Script de carga base

Comentarios

Entradas más populares de este blog

Creación del SP de Cargar Datos

Implementación de funcionalidades: Editar Empleado y Eliminar Empleado

Implementación de funcionalidad: Consultar Empleado