---
marp: true
theme: uncover
paginate: false
size: 16:9
backgroundColor: #f4f5f7
color: #1f2933
style: |
section {
font-size: 1.9em;
}
h1, h2, h3 {
color: #0f172a;
}
/* Texto secundario */
p, li {
color: #1f2933;
}
/* Cajas destacadas */
.box {
border: 3px solid #2563eb;
padding: 1em;
border-radius: 12px;
background-color: #e0e7ff;
color: #1e293b;
}
.columns {
display: flex;
gap: 1em;
justify-content: center;
align-items: stretch;
}
.box.warning {
border-color: #f97316;
background-color: #ffedd5;
}
/* Alineación */
.left {
text-align: left;
}
/* Código */
pre, code {
background-color: #e5e7eb;
color: #111827;
}
.w-30 { width: 30%; }
.w-40 { width: 40%; }
.w-50 { width: 50%; }
.w-60 { width: 60%; }
.w-70 { width: 70%; }
.w-80 { width: 80%; }
.center {
margin-left: auto;
margin-right: auto;
}
---
# Spring Data
### Capa de persistencia relacional
>Un paseo (de 2h) buceando en código
##### Daniel García Costa
###### 2026
---
## ¿Que vamos a ver?
- **¿Que es Spring Data?**
- **Modelo de dominio**
- **Consultas en Spring Data**
- Métodos de abstracción
- JPQL
- SQL nativo
- **Rendimiento**
- **Optimizaciones**
- **Sistema de ejemplo**
- **Mucho código**
---
## ¿Qué es Spring Data?
Spring Data es el paquete del ecosistema Spring para **acceder a datos de forma consistente**.
- Define un modelo común de acceso a datos
- Orquesta todo lo relacionado con el acceso a datos
- Reduce código repetitivo
- Se integra con distintos motores
---
## Qué NO es Spring Data
Spring Data:
- ❌ No elimina el modelo relacional
- ❌ No es ni sustituye al ORM
- ❌ No optimiza consultas automáticamente
- ❌ No toma decisiones por nosotros
Facilita el acceso a datos, pero las decisiones siguen siendo nuestras.
---
## Capas de Spring Data
**Aplicación**
↓
**Spring Data** — Abstracción de repositorios
Abstracción para definir repositorios y consultas
↓
**JPA** — API estándar de persistencia
Especificación estándar (interfaces y anotaciones)
↓
**Hibernate** — ORM (Object–Relational Mapping)
Traducción y mapeo de objetos a SQL
↓
**JDBC Driver** — Comunicación con la base de datos
Ejecuta SQL contra la base de datos
↓
**Base de datos**
---
## Idea clave
Spring Data facilita el acceso a datos pero **no elimina el modelo relacional**.
- Las queries siguen existiendo
- El SQL sigue ejecutándose
- Las decisiones siguen importando
---
## Modelo relacional
La base de datos trabaja con:
- Tablas
- Filas
- Claves primarias y ajenas
- Tipos simples
- Operaciones SQL
La lógica es estructural y declarativa.
---
## Modelo de dominio
La aplicación trabaja con:
- Objetos
- Relaciones entre entidades
- Comportamiento
- Identidad lógica
- Reglas de negocio
La lógica es orientada a objetos.
---
## El problema central
- El modelo relacional ≠ modelo de dominio
- Los objetos no son filas
- Las relaciones no son joins directos
- El rendimiento no es transparente
¡Necesitamos una capa intermedia!.
---
## ¿Qué consultamos en Spring Data?
En Spring Data **no consultamos tablas**.
Consultamos:
- Entidades de dominio
- Gestionadas por JPA
- Mapeadas a tablas relacionales
---
## Entidad como contrato
Una entidad define:
- Qué datos existen
- Cómo se relacionan
- Cómo se identifican
- Cómo se persisten
La base de datos queda detrás de ese contrato.
*Usamos anotaciones para definir las propiedades y relaciones de nuestras entidades. Pej. @Entity, @Table, @Id, @Column, ...*
---
## ¿Dónde queda el SQL?
Aunque trabajemos con entidades:
- SQL sigue existiendo
- Hibernate lo genera o lo ejecuta
- La base de datos decide el coste (planificador del SGBD)
Spring Data te abstrae de las consultas pero no las elimina.
---
## Repository
Un Repository es:
- Una abstracción
- Orientada al dominio
- Tipada con entidades
- Independiente del motor SQL
Es la frontera entre la aplicación y la persistencia.
---
## Tres formas de consultar datos
En Spring Data podemos consultar usando:
1. Métodos de abstracción del Repository
2. JPQL (`@Query`)
3. SQL nativo (`nativeQuery`)
**A mayor abstracción:**
- Menos control
- Más conveniencia
**A menor abstracción:**
- Más control
- Más responsabilidad
---
## Rendimiento
Cuando trabajamos con bases de datos:
- Todas las consultas tienen coste
- El volumen de datos importa
- La abstracción no es gratuita
El rendimiento depende de cómo accedemos a los datos
---
## ¿La abstracción es más lenta?
Pues... No siempre.
Depende de:
- La consulta
- El volumen de datos
- El uso de entidades o proyecciones
- El trabajo extra del ORM
El problema no es la abstracción, es lo qué se pide a la base de datos.
---
## Costes ocultos habituales
- Cargar entidades completas
- Inicializar relaciones
- Consultas innecesarias
- `N+1 SELECT`
- Transferencia de datos excesiva
Muchos problemas no vienen del SQL, sino del modelo de acceso.
---
### Ejemplo N+1 SELECT
```
SELECT t1.*, t2.*, ((t1.actual/t2.total)*100) DIV 1 AS progreso,
CASE WHEN t1.actual = t2.total AND t1.nbpar = t2.total AND t1.nbcomp = 1 THEN 'bg-success'
WHEN actual > 0 AND t1.fact <> factorial(actual) AND t1.nbcomp = 1 THEN 'bg-success'
WHEN t1.nbpar = t2.total AND t1.nbcomp = 0 THEN 'bg-danger'
WHEN actual > 0 AND t1.fact = factorial(actual) THEN 'bg-info'
WHEN actual > 0 AND t1.fact <> factorial(actual) AND t1.nbcomp = 0 THEN 'bg-warning'
WHEN t1.discard = 1 THEN 'bg-secondary'
ELSE 'text-black'
END AS class,
CASE
WHEN t1.actual = t2.total AND t1.nbpar < t2.total AND t1.nbcomp = 1 THEN '*'
ELSE ''
END AS aux
FROM
(SELECT al.usuario, al.id_alumno, al.observaciones AS obs, al.muerto AS discard, MAX(n_problema) AS actual,
CAST(SUM(CASE WHEN completa = 0 THEN 1 ELSE 0 END) AS SIGNED) AS nbpar,
CAST(SUM(CASE WHEN completa = 1 THEN 1 ELSE 0 END)AS SIGNED) AS nbcomp,
SUM(n_problema) AS fact
FROM awpsolver.resultados_json rj
LEFT JOIN awpsolver.alumnos al ON al.id_alumno = rj.id_alumno
WHERE rj.id_grupo_experimento = :v
GROUP BY al.usuario, al.id_alumno
UNION
SELECT al.usuario, al.id_alumno, al.observaciones AS obs, al.muerto AS discard, 0 AS actual,
0 AS nbpar, 0 AS nbcomp, 0 AS self_fact
FROM awpsolver.alumnos al
LEFT JOIN grupos_experimentos ge ON al.id_grupo = ge.id_grupo
WHERE ge.id_grupo_experimento = :v AND al.id_alumno NOT IN(
SELECT id_alumno FROM awpsolver.resultados_json WHERE id_grupo_experimento = :v)
ORDER BY 2) AS t1,
(SELECT COUNT(*) AS total, factorial(COUNT(*)) AS fact FROM awpsolver.problemas WHERE id_experimento
IN(SELECT id_experimento FROM awpsolver.grupos_experimentos WHERE id_grupo_experimento = :v)) AS t2;
```
---
## JPQL vs SQL nativo
Ambos ejecutan SQL.
Diferencias:
- JPQL prioriza el modelo de dominio
- SQL nativo prioriza el modelo relacional
- El control es distinto
El rendimiento depende más de la query que del lenguaje.
---
## Algunas técnicas para reducir coste
**Queries específicas**
Aprovecha la potencia de la BD no tengas miedo a escribir 100 lineas de SQL
**Proyecciones**
Traer solo lo necesario (tablas intermedias, vistas materizalidas, ...).
**Agregados**
(`COUNT`, `SUM`, `AVG`) sobre el SGBD y no en dominio
**Paginación real**
Traer solo lo necesario, no todo + filtro posterior
- Menos columnas = Menos memoria
- Menos trabajo del ORM
- Menos transferencia de datos
Son la primera herramienta antes de optimizar consultas.
---
## Y todo eso... ¿como lo vemos?
Simulación de un juego de estrategia MMO (multijugador masivo en línea) multimundo.
- **Servidor Shard (mundo)**
- Aloja jugadores
- Contiene la dinámica del juego
- Reenvía los eventos al Master
- **Servidor Master (coordinador)**
- Recibe eventos de los Shard, consulta estados, jugadores, rankings, etc.
---
## Arquitectura
- **Servidor Master**
- Monolítico (un único servicio)
- División lógica en controladores -> servicios -> repositorios
- Solo recibe y agrega información
- GUI de consulta
- **Servidor Shard**
- Dos servicios (Persistence + Core)
- Gestiona los eventos de los jugadores
- GUI para simular jugadores
- Reenvío de eventos a Master
---
## ¿Por qué esta arquitectura?
- Separación clara de responsabilidades
- Escalado horizontal de shards
- Aislamiento del dominio de juego
- Centralización de analítica
- Escenario realista para estudiar consultas
---

---
## Clona los siguientes proyectos
- **Master**
- https://inmaculados.uv.es/dagarcos/PSIM-master
- **Shard(s)**
- https://inmaculados.uv.es/dagarcos/PSIM-shard-core
- https://inmaculados.uv.es/dagarcos/PSIM-shard-persistence
#### Y ahora... ¡a ver código!