Configuración de Múltiples Fuentes de Datos en Spring Boot con Oracle y H2

En escenarios de procesamiento de datos por lotes o migración, es común necesitar leer grandes volúmenes de información de una base de datos robusta como Oracle, mientras se registra el progreso de la ejecución (por ejemplo, el último ID procesado o una marca de tiempo) en una base de datos ligera y embebida como H2. Esto permite reanudar la tarea desde el punto exacto donde se detuvo en la siguiente ejecución.

Para lograr esta arquitectura en Spring Boot, utilizaremos la librería dynamic-datasource de Baomidou junto con el pool de conexiones Druid.

  1. Configuración de Dependencias Maven

Primero, incorporamos los controladores JDBC necesarios para Oracle y H2, el starter de Druid y el componente de enrutamiento dinámico de fuentes de datos.

<dependencies>
    <!-- Controlador JDBC para Oracle -->
    <dependency>
        <groupId>com.oracle.database.jdbc</groupId>
        <artifactId>ojdbc8</artifactId>
        <version>19.8.0.0</version>
    </dependency>

    <!-- Base de datos embebida H2 -->
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </dependency>

    <!-- Pool de conexiones Druid -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
        <version>1.2.18</version>
    </dependency>

    <!-- Enrutador dinámico de fuentes de datos -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
        <version>3.5.2</version>
    </dependency>
</dependencies>
  1. Definición de las Fuentes de Datos en application.yml

En el archivo de configuración, definimos un datasource principal orientado a la base de datos Oracle y uno secundario para la base de datos H2 que actuará como regitsro de estado. Hemos renombrado las claves para que reflejen mejor su propósito empresarial.

spring:
  datasource:
    dynamic:
      primary: oracle_main
      strict: false
      datasource:
        oracle_main:
          url: jdbc:oracle:thin:@//192.168.1.100:1521/XEPDB1
          username: admin_user
          password: secure_password
          driver-class-name: oracle.jdbc.OracleDriver
        h2_tracker:
          url: jdbc:h2:file:./data/progress_db;AUTO_SERVER=TRUE
          username: sa
          password: 
          driver-class-name: org.h2.Driver
  1. Implementación de la Capa de Servicio

Para dirigir las conusltas a la base de datos correcta, aplicamos la anotación @DS a nivel de clase o método en nuestros servicios. A continuación, se muestra cómo estructurar los servicios para la extracción de datos y el seguiimento del progreso.

Servicio de Extracción de Datos (Oracle)

Este servicio se encarga de interactuar con la base de datos principal para obtener los registros pendientes.

import com.baomidou.dynamic.datasource.annotation.DS;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;

@Service
@DS("oracle_main")
public class OracleExtractionService {

    private final CoreDataRepository coreDataRepository;

    public OracleExtractionService(CoreDataRepository coreDataRepository) {
        this.coreDataRepository = coreDataRepository;
    }

    public List<Map<String, Object>> fetchBatchById(String schema, String tableName, Long lastProcessedId, int batchSize) {
        return coreDataRepository.selectBatchRecords(schema, tableName, lastProcessedId, batchSize);
    }

    public List<Map<String, Object>> fetchBatchByTimestamp(String schema, String tableName, String timeColumn, Long startEpoch, Long endEpoch) {
        return coreDataRepository.selectRecordsByTimeRange(schema, tableName, timeColumn, startEpoch, endEpoch);
    }
}

Servicio de Seguimiento de Progreso (H2)

Este servicio gestiona la lectura y actualización de los puntos de control (checkpoints) en la base de datos embebida.

import com.baomidou.dynamic.datasource.annotation.DS;
import org.springframework.stereotype.Service;

@Service
@DS("h2_tracker")
public class ProgressTrackerService {

    private final CheckpointRepository checkpointRepository;

    public ProgressTrackerService(CheckpointRepository checkpointRepository) {
        this.checkpointRepository = checkpointRepository;
    }

    public Long getLastProcessedId(String jobName) {
        CheckpointEntity checkpoint = checkpointRepository.findByJobName(jobName);
        return (checkpoint != null) ? checkpoint.getLastId() : 0L;
    }

    public void saveCurrentProgress(String jobName, Long currentId, Long currentTime) {
        checkpointRepository.upsertCheckpoint(jobName, currentId, currentTime);
    }

    public void initializeJob(String jobName) {
        if (!checkpointRepository.existsByJobName(jobName)) {
            checkpointRepository.insertNewJob(jobName, System.currentTimeMillis());
        }
    }
}

Etiquetas: spring-boot Oracle h2 dynamic-datasource Druid

Publicado el 7-14 07:02