Explorar o código

slides completed

Daniel Garcia Costa hai 1 mes
pai
achega
e81f5b0220

+ 477 - 0
Slides/SeminarioSpringData_2026.md

@@ -0,0 +1,477 @@
+---
+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
+
+<br/>
+<br/>
+
+##### 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
+
+<br>
+<div class="box w-90 center">
+Facilita el acceso a datos, pero <strong>las decisiones siguen siendo nuestras</strong>.
+</div>
+
+---
+
+## Capas de Spring Data
+
+**Aplicación**  
+↓  
+**Spring Data** — Abstracción de repositorios  
+<small>Abstracción para definir repositorios y consultas</small>
+↓  
+**JPA** — API estándar de persistencia  
+<small>Especificación estándar (interfaces y anotaciones)</small>
+↓  
+**Hibernate** — ORM (Object–Relational Mapping)  
+<small>Traducción y mapeo de objetos a SQL</small>
+↓  
+**JDBC Driver** — Comunicación con la base de datos  
+<small>Ejecuta SQL contra la base de datos</small>
+↓  
+**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
+
+<br>
+<div class="box w-60 center">
+La lógica es <strong>estructural y declarativa</strong>.
+</div>
+
+---
+
+## Modelo de dominio
+
+La aplicación trabaja con:
+
+- Objetos
+- Relaciones entre entidades
+- Comportamiento
+- Identidad lógica
+- Reglas de negocio
+
+<br>
+<div class="box w-50 center">
+La lógica es <strong>orientada a objetos</strong>.
+</div>
+
+---
+
+## 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
+
+<br>
+<div class="box w-50 center">
+<strong>¡Necesitamos una capa intermedia!</strong>.
+</div>
+
+
+---
+
+## ¿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
+
+<br>
+<div class="box w-70 center">
+<strong>La base de datos queda detrás de ese contrato</strong>.
+</div>
+<br>
+*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)
+
+<br>
+<div class="box w-80 center">
+Spring Data <strong>te abstrae de las consultas</strong> pero <strong>no las elimina</strong>.
+</div>
+
+---
+
+## Repository
+
+Un Repository es:
+
+- Una abstracción
+- Orientada al dominio
+- Tipada con entidades
+- Independiente del motor SQL
+
+<br>
+<div class="box w-70 center">
+Es la <strong>frontera</strong> entre la aplicación y la persistencia.
+</div>
+
+---
+
+## 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`)
+
+<br>
+<div class="box  warning w-30 center">
+
+**A mayor abstracción:**
+- Menos control
+- Más conveniencia
+
+**A menor abstracción:**
+- Más control
+- Más responsabilidad
+
+</div>
+
+---
+
+## Rendimiento
+
+Cuando trabajamos con bases de datos:
+
+- Todas las consultas tienen coste
+- El volumen de datos importa
+- La abstracción no es gratuita
+<br>
+<div class="box w-80 center">
+El rendimiento depende de <strong>cómo accedemos a los datos</strong>
+</div>
+
+---
+
+## ¿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
+
+<br>
+<div class="box w-90 center">
+El problema no es la abstracción, es lo <strong>qué se pide a la base de datos</strong>.
+</div>
+
+---
+
+## Costes ocultos habituales
+
+- Cargar entidades completas
+- Inicializar relaciones
+- Consultas innecesarias
+- `N+1 SELECT`
+- Transferencia de datos excesiva
+
+<br>
+<div class="box w-90 center">
+Muchos problemas no vienen del SQL, sino del <strong>modelo de acceso</strong>.
+</div>
+
+---
+
+### 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
+
+<br>
+<div class="box w-90 center">
+El rendimiento depende más de la query que del lenguaje.
+</div>
+
+
+---
+
+## 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
+<br>
+<div class="columns">
+  <div class="box warning w-50 center">
+
+  - Menos columnas = Menos memoria
+  - Menos trabajo del ORM
+  - Menos transferencia de datos
+  </div>
+  <div class="box w-40 center">
+      <strong>Son la primera herramienta antes de optimizar consultas.</strong>
+  </div>
+</div>
+
+---
+
+## Y todo eso... ¿como lo vemos?
+
+Simulación de un juego de estrategia MMO (multijugador masivo en línea) multimundo. 
+<br>
+- **Servidor Shard (mundo)**
+    - Aloja jugadores
+    - Contiene la dinámica del juego
+    - Reenvía los eventos al Master
+<br>
+- **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
+<br>
+- **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
+
+---
+
+
+![Arquitectura del sistema](diagrama_componentes.png)
+
+---
+
+## Clona los siguientes proyectos
+
+- **Master**
+  - https://inmaculados.uv.es/dagarcos/PSIM-master
+<br>
+- **Shard(s)**
+  - https://inmaculados.uv.es/dagarcos/PSIM-shard-core
+  - https://inmaculados.uv.es/dagarcos/PSIM-shard-persistence
+
+<br>
+
+#### Y ahora... ¡a ver código!

BIN=BIN
Slides/SeminarioSpringData_2026.pdf


BIN=BIN
Slides/diagrama_componentes.png


+ 76 - 0
Slides/diagrama_seminario.drawio

@@ -0,0 +1,76 @@
+<mxfile host="app.diagrams.net" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36" version="29.6.1">
+  <diagram name="Arquitectura Master-Shard" id="0">
+    <mxGraphModel dx="1426" dy="1871" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1920" pageHeight="1080" math="0" shadow="0">
+      <root>
+        <mxCell id="0" />
+        <mxCell id="1" parent="0" />
+        <mxCell id="shard" parent="1" style="swimlane;horizontal=0;startSize=30;fillColor=#E3F2FD;strokeColor=#1565C0;fontSize=16;" value="Servidor Shard" vertex="1">
+          <mxGeometry height="420" width="420" x="40" y="80" as="geometry" />
+        </mxCell>
+        <mxCell id="shardCore" parent="shard" style="rounded=1;fillColor=#BBDEFB;fontSize=16;fontStyle=1" value="Core Service&#xa;(Lógica de juego)" vertex="1">
+          <mxGeometry height="70" width="320" x="40" y="60" as="geometry" />
+        </mxCell>
+        <mxCell id="shardPersistence" parent="shard" style="rounded=1;fillColor=#BBDEFB;fontSize=16;fontStyle=1" value="Persistence Service&#xa;(Spring Data / JPA)" vertex="1">
+          <mxGeometry height="70" width="320" x="40" y="150" as="geometry" />
+        </mxCell>
+        <mxCell id="shardDB" parent="shard" style="shape=cylinder;fillColor=#E1F5FE;fontSize=16;fontStyle=1" value="&#xa;Shard DB&#xa;" vertex="1">
+          <mxGeometry height="80" width="160" x="120" y="260" as="geometry" />
+        </mxCell>
+        <mxCell id="AlSRsDaISVzWPFBxWCj3-3" parent="shard" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;fontStyle=0" value="&lt;span&gt;&lt;font style=&quot;font-size: 16px;&quot;&gt;:8021&lt;/font&gt;&lt;/span&gt;" vertex="1">
+          <mxGeometry height="30" width="60" x="300" y="170" as="geometry" />
+        </mxCell>
+        <mxCell id="AlSRsDaISVzWPFBxWCj3-4" parent="shard" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;fontStyle=0" value="&lt;span&gt;&lt;font style=&quot;font-size: 16px;&quot;&gt;:8020&lt;/font&gt;&lt;/span&gt;" vertex="1">
+          <mxGeometry height="30" width="60" x="300" y="80" as="geometry" />
+        </mxCell>
+        <mxCell id="master" parent="1" style="swimlane;horizontal=0;startSize=30;fillColor=#FFF3E0;strokeColor=#EF6C00;fontSize=16;" value="Servidor Master" vertex="1">
+          <mxGeometry height="420" width="420" x="640" y="80" as="geometry" />
+        </mxCell>
+        <mxCell id="masterAPI" parent="master" style="rounded=1;fillColor=#FFE0B2;fontSize=16;fontStyle=1" value="API REST&#xa;(Controladores)" vertex="1">
+          <mxGeometry height="60" width="320" x="40" y="60" as="geometry" />
+        </mxCell>
+        <mxCell id="masterService" parent="master" style="rounded=1;fillColor=#FFE0B2;fontSize=16;fontStyle=1" value="Servicios&#xa;(Agrupación / Estadísticas)" vertex="1">
+          <mxGeometry height="60" width="320" x="40" y="140" as="geometry" />
+        </mxCell>
+        <mxCell id="masterRepo" parent="master" style="rounded=1;fillColor=#FFE0B2;fontSize=16;fontStyle=1" value="Repositorios&#xa;(Spring Data)" vertex="1">
+          <mxGeometry height="60" width="320" x="40" y="220" as="geometry" />
+        </mxCell>
+        <mxCell id="masterDB" parent="master" style="shape=cylinder;fillColor=#FFF8E1;fontSize=16;fontStyle=1" value="&#xa;Master DB&#xa;" vertex="1">
+          <mxGeometry height="80" width="160" x="120" y="310" as="geometry" />
+        </mxCell>
+        <mxCell id="AlSRsDaISVzWPFBxWCj3-5" parent="master" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;fontStyle=0" value="&lt;span&gt;&lt;font style=&quot;font-size: 16px;&quot;&gt;:8010&lt;/font&gt;&lt;/span&gt;" vertex="1">
+          <mxGeometry height="30" width="60" x="350" y="10" as="geometry" />
+        </mxCell>
+        <mxCell id="gui" parent="1" style="rounded=1;fillColor=#E8F5E9;strokeColor=#2E7D32;fontSize=16;fontStyle=1" value="GUI de Consulta" vertex="1">
+          <mxGeometry height="80" width="420" x="630" y="-40" as="geometry" />
+        </mxCell>
+        <mxCell id="e1" edge="1" parent="1" source="shardCore" style="endArrow=block;" target="shardPersistence">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="e2" edge="1" parent="1" source="shardPersistence" style="endArrow=block;" target="shardDB">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="e3" edge="1" parent="1" source="shardCore" style="endArrow=block;exitX=1;exitY=0.5;exitDx=0;exitDy=0;fontStyle=1;fontSize=13;labelBackgroundColor=none;" target="masterAPI" value="HTTP&#xa;Eventos + Heartbeat">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="e4" edge="1" parent="1" source="masterAPI" style="endArrow=block;fontStyle=1" target="masterService">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="e5" edge="1" parent="1" source="masterService" style="endArrow=block;fontStyle=1" target="masterRepo">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="e6" edge="1" parent="1" source="masterRepo" style="endArrow=block;" target="masterDB">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="e7" edge="1" parent="1" source="gui" style="endArrow=block;" target="masterAPI" value="">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="AlSRsDaISVzWPFBxWCj3-2" edge="1" parent="1" source="AlSRsDaISVzWPFBxWCj3-1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" target="shardCore">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="AlSRsDaISVzWPFBxWCj3-1" parent="1" style="rounded=1;fillColor=#E8F5E9;strokeColor=#2E7D32;fontSize=18;fontStyle=1" value="GUI del juego" vertex="1">
+          <mxGeometry height="80" width="380" x="50" y="-40" as="geometry" />
+        </mxCell>
+      </root>
+    </mxGraphModel>
+  </diagram>
+</mxfile>

+ 0 - 75
Slides/slides.md

@@ -1,75 +0,0 @@
----
-marp: true
-theme: uncover
-paginate: false
-size: 16:9
-backgroundColor: #0f172a
-color: #e5e7eb
-style: |
-  section {
-    font-size: 2em;
-  }
----
-
-# Spring Data
-
-### Capa de persistencia relacional
-
-<br/>
-<br/>
-
-##### Daniel García Costa  
-###### 2026
-
----
-
-## ¿Que vamos a ver?
-
-- **Contexto y arquitectura del sistema**
-- **Modelo relacional vs modelo de dominio**
-- **Consultas en Spring Data**
-  - Métodos de abstracción
-  - JPQL
-  - SQL nativo
-- **Proyecciones, agregados y rankings**
-- **Paginación y filtrado con `Pageable`**
-- **Optimizaciones**
-
----
-
-## Contexto
-
-Simulación de un juego MMO (multijugador masivo en línea) multimundo. 
-
-- **Servidor Master (coordinador)**
-    - Recibe eventos de los Shard, consulta estados, jugadores, rankings, etc.
-- **Servidor Shard (mundo)**
-    - Aloja jugadores
-    - Contiene la dinámica del juego
-    - Reenvía los eventos al Master
-
----
-## 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
-
----