====== 07 - Persistencia con JPA ====== El punto débil que dejó el [[proyecto:06-modulos-modulith|hito 06]] — stock reservado sin pedido cuando la persistencia falla — es el mejor argumento para este hito. Aplica el [[temario:05-spring-jpa|tema 05 — Persistencia: Spring JPA]]: la inversión de dependencias ya existe desde la partida — las interfaces de repositorio viven en ''domain'' —, así que lo que cambia es el mecanismo detrás de ellas: la persistencia **JDBC** se sustituye por **JPA**/**Hibernate**, repositorios de **Spring Data** y mapeos con **MapStruct**, sin tocar dominio, casos de uso, contrato ni API pública. La paginación a mano con JDBC también desaparece: **Spring Data** la resuelve. ^ Pieza ^ Cambio en este hito ^ | Persistencia | DAO JDBC → entidades **JPA** y repositorios **Spring Data**, en cada módulo | | Dominio | Sin cambios: las interfaces de repositorio siguen definidas en ''domain'' | | Paginación | ''LIMIT''/''OFFSET'' a mano → **Pageable**/**Page** de **Spring Data** | | Mapeos | **MapStruct** entre entidades y modelos del dominio | | Transacciones | Crear y cancelar pedidos se vuelven atómicos | | Pruebas | **Testcontainers**: MariaDB real en las pruebas de persistencia | ===== 1. El nuevo mecanismo de persistencia ===== * Dependencia **Data JPA** de Spring (el driver de MariaDB ya entró con la partida). El esquema lo sigue gestionando el ''init.sql'': las entidades **mapean** contra él y no lo generan. * Entidades **JPA** para las tablas de cada módulo, con sus relaciones — el producto con su catálogo, el pedido con sus líneas — según las decisiones que muestra el [[temario:05-spring-jpa|tema 05]]. * Repositorios de **Spring Data** junto a las entidades: las consultas se derivan de la firma de sus métodos. La paginación del catálogo pasa a lo que ya trae — el ''Pageable'' entra y la ''Page'' devuelve el contenido y los metadatos que el contrato declara —: el recuento a mano del [[proyecto:04-api-first|hito 04]] desaparece. * Las implementaciones de las interfaces del dominio se reconstruyen sobre las piezas nuevas, y los mapeos entre entidades y modelos del dominio se declaran con **MapStruct** del modo que muestra el tema. El dominio sigue sin conocer JPA, MapStruct ni Spring: se comprueba en los imports de sus clases. ===== 2. Transacciones ===== * Crear un pedido pasa a ser una **transacción**: reservar todas las líneas y persistir el pedido comparten el mismo contexto y la misma base de datos; si una línea falla, la excepción hace ''rollback'' de todo — el stock queda como estaba y el pedido no se crea. La protección a mano del [[proyecto:06-modulos-modulith|hito 06]] desaparece. * Cancelar también: liberar el stock y cambiar el estado, atómicos. La transacción cruza módulos porque escriben en la misma base de datos. Es el piso del tema 08: una operación auxiliar — enviar la factura, avisar de stock bajo — no debería entrar en esa transacción; de ahí los eventos. ===== 3. Pruebas de persistencia ===== Criterio del nivel: las pruebas del repositorio van contra la **base de datos real** del proyecto, no contra un sustituto. La decisión de la práctica: **Testcontainers** con la misma imagen de **MariaDB** del curso (fijada en la [[proyecto:02-especificacion|especificación]]). * **Catálogo**: guardar y recuperar mantiene el producto intacto — catálogo, precio y stock como corresponden; listar; borrar. * **Paginación**: el listado de un catálogo respeta tamaño, orden y totales, con los metadatos que **Spring Data** aporta. * **Pedidos**: guardar cabecera y líneas; recuperar el pedido con sus líneas y sus precios capturados. * **Transacción**: crear un pedido cuya segunda línea no tiene stock deja el catálogo sin cambios y sin pedido — la prueba integra ambos módulos sobre el contenedor. * Las pruebas anteriores no cambian: dominio sin base de datos, presentación con dobles, límites con sus verificaciones. ===== Comprobación ===== * Ya no queda JDBC: todo acceso a datos pasa por las interfaces de repositorio del dominio, implementadas en ''persistence'' con JPA. * El listado paginado responde igual que en el hito 04, pero sin SQL de paginación escrito a mano. * El dominio no importa JPA, MapStruct ni Spring (comprobar con los imports y con las reglas ArchUnit). * Las pruebas de persistencia corren contra MariaDB en Testcontainers. * Un pedido con una línea imposible no deja nada a medias: transacción probada. * El contrato no cambia (sin subida de versión); commit y tag ''hito-07''. **Siguiente hito:** [[proyecto:08-login-jwt|hito 08 — Login con JWT]].