Saltar al contenido principal

Capítulo 1: Configuración de Datasources

Introducción​

Cada vez que su aplicación Spring Boot interactúa con la base de datos, utiliza una conexión. Pero, ¿de dónde provienen estas conexiones? ¿Cómo se gestionan? Ese es el papel de la Datasource.


🎯 Objetivos del Capítulo​

Al final de este capítulo, usted sabrá:

  1. ✅ Qué es una Datasource y por qué es importante
  2. ✅ Cómo Spring Boot configura automáticamente las conexiones
  3. ✅ Configurar HikariCP (el pool por defecto)
  4. ✅ Optimizar los parámetros para producción
  5. ✅ Configurar múltiples datasources

1. ¿Qué es una Datasource?​

Definición Simple​

Una Datasource es un objeto que proporciona conexiones a la base de datos.

El Problema Sin Pool de Conexiones​

// ❌ MALA PRÁCTICA: Nueva conexión en cada consulta
public void getUser(Long id) {
Connection conn = DriverManager.getConnection(url, user, password);
// ... usar la conexión
conn.close();
}

Problemas:

  • Crear una conexión = 500ms a 1s (¡muy lento!)
  • 100 usuarios simultáneos = 100 conexiones = base de datos saturada
  • Sin reutilización = desperdicio de recursos

La Solución: Pool de Conexiones​

// ✅ BUENA PRÁCTICA: Reutilizar las conexiones
public void getUser(Long id) {
Connection conn = dataSource.getConnection(); // ← Conexión del pool (< 1ms)
// ... usar la conexión
conn.close(); // ← Retorna al pool (no se cierra realmente)
}

Ventajas:

  • Conexiones pre-creadas = respuesta instantánea
  • Reutilización = menos carga sobre la base de datos
  • Limita el número máximo de conexiones

2. HikariCP: El Pool por Defecto​

¿Por qué HikariCP?​

Spring Boot utiliza HikariCP (光 = "luz" en japonés) porque es:

  • 🚀 El más rápido (benchmarks comprobados)
  • 💪 El más confiable (utilizado por grandes empresas)
  • 🔧 Fácil de configurar

Auto-Configuración de Spring Boot​

Cuando usted añade una dependencia de base de datos, Spring Boot configura automáticamente HikariCP:

<!-- pom.xml -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<!-- ¡HikariCP está incluido automáticamente! -->
</dependency>

3. Configuración Básica​

Configuración Mínima (H2)​

# application.properties
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=

Configuración PostgreSQL​

# application.properties
spring.datasource.url=jdbc:postgresql://localhost:5432/mydb
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.username=postgres
spring.datasource.password=secret

Configuración MySQL​

# application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=secret

4. Configuración Avanzada de HikariCP​

Parámetros Esenciales​

# application.properties

# Tamaño del pool
spring.datasource.hikari.minimum-idle=5 # Conexiones mínimas mantenidas
spring.datasource.hikari.maximum-pool-size=10 # Conexiones máximas

# Timeouts
spring.datasource.hikari.connection-timeout=30000 # Espera máxima para obtener una conexión (30s)
spring.datasource.hikari.idle-timeout=600000 # Tiempo antes de cerrar una conexión inactiva (10min)
spring.datasource.hikari.max-lifetime=1800000 # Vida máxima de una conexión (30min)

# Nombre del pool (para logs)
spring.datasource.hikari.pool-name=MyAppPool

Visualización del Pool​

┌─────────────────────────────────────────────────────┐
│ HikariCP Pool │
│ │
│ minimum-idle=5 maximum-pool-size=10 │
│ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │Conn1│ │Conn2│ │Conn3│ │Conn4│ │Conn5│ (idle) │
│ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ │
│ │
│ + 5 conexiones adicionales si es necesario │
│ │
│ connection-timeout=30s (espera máxima si pool lleno)│
└─────────────────────────────────────────────────────┘

Formato YAML (Alternativa)​

# application.yml
spring:
datasource:
url: jdbc:postgresql://localhost:5432/mydb
username: postgres
password: secret
hikari:
minimum-idle: 5
maximum-pool-size: 10
connection-timeout: 30000
idle-timeout: 600000
max-lifetime: 1800000
pool-name: MyAppPool

5. Recomendaciones por Entorno​

Desarrollo (H2)​

# application-dev.properties
spring.datasource.url=jdbc:h2:mem:devdb
spring.datasource.hikari.minimum-idle=2
spring.datasource.hikari.maximum-pool-size=5

# Consola H2 activada
spring.h2.console.enabled=true

Producción (PostgreSQL)​

# application-prod.properties
spring.datasource.url=jdbc:postgresql://db.server.com:5432/proddb
spring.datasource.hikari.minimum-idle=10
spring.datasource.hikari.maximum-pool-size=50

# ¡Sin consola H2!
spring.h2.console.enabled=false

# Validación de conexiones
spring.datasource.hikari.connection-test-query=SELECT 1

Fórmula para maximum-pool-size​

Regla empírica:
maximum-pool-size = (número de CPU * 2) + número de discos

Ejemplo:
- Servidor con 4 CPU y 1 disco SSD
- Pool size = (4 * 2) + 1 = 9 ≈ 10
tip

¡No sobredimensione! Un pool demasiado grande puede degradar el rendimiento porque la base de datos debe gestionar demasiadas conexiones simultáneas.


6. Configuración Multi-Datasources​

Caso de Uso​

A veces, una aplicación debe conectarse a varias bases de datos:

Configuración​

# application.properties

# Datasource primaria (PostgreSQL)
spring.datasource.primary.url=jdbc:postgresql://localhost:5432/usersdb
spring.datasource.primary.username=postgres
spring.datasource.primary.password=secret
spring.datasource.primary.driver-class-name=org.postgresql.Driver

# Datasource secundaria (MySQL)
spring.datasource.secondary.url=jdbc:mysql://localhost:3306/productsdb
spring.datasource.secondary.username=root
spring.datasource.secondary.password=secret
spring.datasource.secondary.driver-class-name=com.mysql.cj.jdbc.Driver

Configuración Java​

@Configuration
public class DataSourceConfig {

// Datasource primaria
@Primary
@Bean(name = "primaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.primary")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}

// Datasource secundaria
@Bean(name = "secondaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.secondary")
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().build();
}
}

Uso con JPA​

// Configuración EntityManager para Primary
@Configuration
@EnableJpaRepositories(
basePackages = "com.example.repository.users",
entityManagerFactoryRef = "primaryEntityManager",
transactionManagerRef = "primaryTransactionManager"
)
public class PrimaryDatabaseConfig {
// ... configuración
}

// Configuración EntityManager para Secondary
@Configuration
@EnableJpaRepositories(
basePackages = "com.example.repository.products",
entityManagerFactoryRef = "secondaryEntityManager",
transactionManagerRef = "secondaryTransactionManager"
)
public class SecondaryDatabaseConfig {
// ... configuración
}

7. Monitoreo del Pool​

Vía Actuator​

Agregue Spring Boot Actuator para monitorear el pool:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
# application.properties
management.endpoints.web.exposure.include=health,metrics
management.endpoint.health.show-details=always

Métricas Disponibles​

# Verificar el pool
GET /actuator/metrics/hikaricp.connections

# Conexiones activas
GET /actuator/metrics/hikaricp.connections.active

# Conexiones en espera
GET /actuator/metrics/hikaricp.connections.pending

# Timeouts
GET /actuator/metrics/hikaricp.connections.timeout

Ejemplo de Respuesta​

{
"name": "hikaricp.connections.active",
"measurements": [
{
"statistic": "VALUE",
"value": 3.0
}
],
"availableTags": [
{
"tag": "pool",
"values": ["MyAppPool"]
}
]
}

8. Problemas Comunes y Soluciones​

❌ Connection Timeout​

HikariPool-1 - Connection is not available, request timed out after 30000ms.

Causas:

  • Pool demasiado pequeño
  • Conexiones no cerradas (fuga)
  • Consultas demasiado lentas

Soluciones:

# Aumentar el pool
spring.datasource.hikari.maximum-pool-size=20

# Aumentar el timeout
spring.datasource.hikari.connection-timeout=60000

# Activar logs de fuga
spring.datasource.hikari.leak-detection-threshold=60000

❌ Too Many Connections​

PostgreSQL: FATAL: too many connections for role "postgres"

Causa: Pool demasiado grande o varias instancias

Solución:

# Reducir el pool
spring.datasource.hikari.maximum-pool-size=5

# Verificar el max_connections de PostgreSQL
# SHOW max_connections;

❌ Connection Leak​

HikariPool-1 - Connection leak detection triggered

Causa: Conexión nunca retornada al pool

Solución:

# Activar la detección de fuga
spring.datasource.hikari.leak-detection-threshold=30000

Luego encontrar y corregir el código defectuoso (conexión no cerrada).


9. Resumen​

Puntos Clave​

ConceptoDescripción
DatasourceProporciona las conexiones a la base de datos
HikariCPPool de conexiones por defecto (el más rápido)
minimum-idleConexiones mínimas mantenidas
maximum-pool-sizeConexiones máximas
connection-timeoutTiempo máximo para obtener una conexión

Checklist de Configuración​

✅ Definir spring.datasource.url
✅ Definir username/password
✅ Configurar minimum-idle y maximum-pool-size
✅ Ajustar los timeouts según el entorno
✅ Monitorear con Actuator

Configuración Recomendada​

# Producción
spring.datasource.url=jdbc:postgresql://localhost:5432/mydb
spring.datasource.username=myuser
spring.datasource.password=${DB_PASSWORD}

spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.maximum-pool-size=20
spring.datasource.hikari.connection-timeout=30000
spring.datasource.hikari.idle-timeout=600000
spring.datasource.hikari.max-lifetime=1800000
spring.datasource.hikari.pool-name=MyAppPool

🎯 Próximo Paso​

Ahora que usted comprende cómo se gestionan las conexiones, es momento de aprender cómo proteger la integridad de sus datos con las transacciones.

➡️ Capítulo 2: Gestión de Transacciones (@Transactional)


⬅️ Volver al Módulo 7