Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Recopie MS-SQL vers PostgreSQL

APERTO-NOTA

Principe

La route lit la table source par lots de 1 000 lignes (OFFSET / FETCH) jusqu’à épuisement, transforme chaque ligne et l’insère dans PostgreSQL. Le déclenchement est manuel via un appel REST.


Configuration des datasources

Créer le fichier camel/application.properties :

# Datasource MS-SQL
camel.datasource.mssql.url=jdbc:sqlserver://mssql:1433;databaseName=sourcedb;encrypt=false
camel.datasource.mssql.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver
camel.datasource.mssql.username=sa
camel.datasource.mssql.password=Str0ngPass!

# Datasource PostgreSQL
camel.datasource.postgres.url=jdbc:postgresql://postgres:5432/targetdb
camel.datasource.postgres.driver-class-name=org.postgresql.Driver
camel.datasource.postgres.username=camel
camel.datasource.postgres.password=camel

# Taille des lots
sync.batch.size=1000

Route Camel (YAML)

Trois routes : déclencheur REST, boucle de pagination, traitement d’un lot.

Créer le fichier camel/routes/mssql-to-pg.camel.yaml :

# Route 1 : point d'entrée REST
- route:
    id: sync-trigger
    description: Déclenche la synchronisation sur POST /sync
    from:
      uri: rest:post:sync
    steps:
      - setProperty:
          name: offset
          expression:
            constant: 0
      - setProperty:
          name: totalRows
          expression:
            constant: 0
      - to:
          uri: direct:sync-loop
      - setBody:
          expression:
            simple: "${exchangeProperty.totalRows} lignes synchronisées"

# Route 2 : boucle de pagination
- route:
    id: sync-loop
    description: Lit les lots MS-SQL jusqu'à épuisement
    from:
      uri: direct:sync-loop
    steps:
      - log:
          message: "Lecture lot offset=${exchangeProperty.offset}"

      # Lecture d'un lot
      - setBody:
          expression:
            simple: >
              SELECT id, nom, prix, actif
              FROM dbo.produits
              ORDER BY id
              OFFSET ${exchangeProperty.offset} ROWS
              FETCH NEXT {{sync.batch.size}} ROWS ONLY
      - to:
          uri: jdbc:mssql

      # Arrêt si lot vide
      - choice:
          when:
            - simple: "${body.size()} == 0"
              steps:
                - log:
                    message: "Synchronisation terminée — ${exchangeProperty.totalRows} lignes"
                - stop: {}
          otherwise:
            steps:
              # Traitement du lot
              - to:
                  uri: direct:sync-batch

              # Incrémenter offset et totalRows
              - setProperty:
                  name: offset
                  expression:
                    groovy: >
                      exchange.getProperty('offset', Integer) + {{sync.batch.size}}
              - setProperty:
                  name: totalRows
                  expression:
                    groovy: >
                      exchange.getProperty('totalRows', Integer) + exchange.getProperty('batchSize', Integer)

              # Itération suivante
              - to:
                  uri: direct:sync-loop

# Route 3 : traitement d'un lot
- route:
    id: sync-batch
    description: Transforme et insère un lot dans PostgreSQL
    from:
      uri: direct:sync-batch
    steps:
      - setProperty:
          name: batchSize
          expression:
            simple: "${body.size()}"
      - split:
          expression:
            simple: "${body}"
          steps:
            # Conversion BIT → BOOLEAN
            - setBody:
                expression:
                  groovy: |
                    def row = request.body
                    row['actif'] = row['actif'] == 1
                    return row

            # Upsert PostgreSQL
            - to:
                uri: jdbc:postgres
                body: >
                  INSERT INTO produits (id, nom, prix, actif)
                  VALUES (:#id, :#nom, :#prix, :#actif)
                  ON CONFLICT (id) DO UPDATE
                  SET nom   = EXCLUDED.nom,
                      prix  = EXCLUDED.prix,
                      actif = EXCLUDED.actif

Exécution et vérification

Déclencher la synchronisation

curl -X POST http://localhost:8080/sync

Réponse attendue :

1500000 lignes synchronisées

Vérifier le résultat dans PostgreSQL

docker exec -it camel-postgres psql -U camel -d targetdb \
  -c "SELECT COUNT(*) FROM produits;"

Conversions de types MS-SQL → PostgreSQL

MS-SQLPostgreSQLRemarque
NVARCHARTEXTPas de limite à déclarer
DATETIMETIMESTAMPFormat ISO 8601 automatique
BITBOOLEANConversion explicite nécessaire
DECIMALNUMERICPrécision identique
INT IDENTITYINTEGERPas d’auto-increment côté cible
UNIQUEIDENTIFIERUUIDCast via ::uuid si besoin

Points d’attention