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á:
- ✅ Qué es una Datasource y por qué es importante
- ✅ Cómo Spring Boot configura automáticamente las conexiones
- ✅ Configurar HikariCP (el pool por defecto)
- ✅ Optimizar los parámetros para producción
- ✅ 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
¡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
| Concepto | Descripción |
|---|---|
| Datasource | Proporciona las conexiones a la base de datos |
| HikariCP | Pool de conexiones por defecto (el más rápido) |
| minimum-idle | Conexiones mínimas mantenidas |
| maximum-pool-size | Conexiones máximas |
| connection-timeout | Tiempo 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)