TS
Thomas Schmitz

Freiberuflicher IT-Berater, Softwareentwickler & DevOps. Praxisnahe Artikel zu API-Design, Architektur und Cloud-Workflows.

Serie: Spring Batch · Teil 8 von 12

Spring Batch Teil 8: Datenqualität & Konsistenz

Duplikate, Referenzen, Late Data: wie du Datenqualität messbar und konsistent hältst.

Praxisnah Checkliste

Ein Batch, der einfach durchläuft, kann trotzdem fachlich falsch sein. Genau deshalb brauchen wir Datenqualität als erstklassiges Ziel, nicht als Nachgedanken. Datenqualität heißt: Die Daten sind vollständig, gültig, eindeutig und konsistent. In diesem Teil definieren wir Qualitätsregeln und behandeln Duplikate, Referenzen und Late Data. Außerdem bauen wir einen klaren Prüfpfad.

Zielbild

Nach diesem Kapitel kannst du Datenqualitätsregeln explizit machen, Duplikate und Referenzprobleme gezielt behandeln und einen Prüfpfad definieren, der messbar und auditierbar ist.

Qualitätsdimensionen (Kurzlandkarte)

Die Qualitätsdimensionen sind Vollständigkeit, Gültigkeit, Eindeutigkeit, Konsistenz und Aktualität. Beispiel: Eine fehlende E-Mail verletzt Vollständigkeit, zwei gleiche customer_id verletzen Eindeutigkeit.

Prüfpfad: Staging statt Direktimport

Ein robustes Muster ist:

  1. Rohdaten in eine Staging-Tabelle schreiben.
  2. Qualitätschecks und Bereinigung.
  3. Fachliche Zieltabellen befüllen (idempotent).

Staging heißt: Rohdaten landen zuerst in einer Zwischentabelle. So kannst du die Rohdaten auditieren, ohne sofort produktive Tabellen zu beschädigen. Gerade bei CSV-Imports ist das Gold wert.

Staging hat noch einen zweiten Effekt: Restartability wird eindeutig. Wenn du eine run_id für den Import nutzt und alle Rohdaten mit dieser run_id markierst, liest der Job beim Restart exakt denselben Input. Bei mutierenden DB-Quellen ist das der sicherste Weg, um Lücken und Duplikate zu vermeiden. Warum das bei DB-Readern entscheidend ist und welche Alternativen es gibt, finden wir in Teil 6: JobParameters & Restartability.

Beispiel-Schema für Staging (auf unsere CSV-Domäne zugeschnitten):

staging_customers(
  run_id UUID,
  source_file VARCHAR(255),
  line_number BIGINT,
  customer_id BIGINT,
  first_name VARCHAR(100),
  last_name VARCHAR(100),
  email VARCHAR(255),
  birth_date DATE,
  signup_date DATE,
  loaded_at TIMESTAMP,
  parse_status VARCHAR(16)
)

Quarantine/Rejects: Fehler sichtbar halten

Fehlerhafte Datensätze willst du nicht verlieren. Lege sie in eine separate Reject-Tabelle ab, damit du sie auditieren, korrigieren oder reprocessen kannst. Eine einfache Struktur:

staging_customer_rejects(
  run_id UUID,
  source_file VARCHAR(255),
  line_number BIGINT,
  raw_payload VARCHAR(4000),
  error_code VARCHAR(32),
  error_message VARCHAR(255),
  rejected_at TIMESTAMP
)

So bleibt jeder Fehler sichtbar und du kannst eine fachliche Entscheidung treffen, statt nur einen Skip-Count zu sehen.

Duplikate: fachlich entscheiden

Duplikate sind kein technisches Detail, sondern eine Geschäftsregel. Für unseren Import könnten Regeln so aussehen: customer_id ist eindeutig bedeutet, dass ein Duplikat je nach Schwere zu Fail oder Skip führt. E-Mail doppelt kann eine Warnung mit Skip sein, aber nicht fatal. Gleicher Datensatz erneut sollte idempotent behandelt werden und ist kein Fehler.

Wichtig: Du musst vorab entscheiden, welche Duplikate tolerierbar sind.

Referenzen: Konsistenz zwischen Tabellen

Beispiele: Ein Kunde darf nur existieren, wenn seine country_code bekannt ist. Ein Report darf nur erzeugt werden, wenn alle Kunden geschrieben wurden.

In der Praxis heißt das: Referenzdaten zuerst laden, Foreign Keys in der DB erzwingen, wo sinnvoll, und Staging-Checks für fehlende Referenzen einbauen. Beispiel: Ein Kunde ohne gültigen country_code wird im Check geblockt.

Konkrete Checks (SQL-Skizzen)

Ein paar einfache Checks, die du direkt auf Staging fahren kannst:

-- Duplikate nach customer_id
select customer_id, count(*)
from staging_customers
where run_id = :runId
group by customer_id
having count(*) > 1;

-- Fehlende Referenzen (country_code nicht bekannt)
select s.customer_id
from staging_customers s
left join ref_country c on c.code = s.country_code
where s.run_id = :runId and c.code is null;

-- Ungültige Datumsfelder (Signup in der Zukunft)
select customer_id
from staging_customers
where run_id = :runId and signup_date > current_date;

Diese Checks kannst du als eigene Steps oder als Tasklet vor dem eigentlichen Import ausführen. Wichtig ist: Fehler müssen vor dem Write sichtbar sein.

Late Data: verspätete Korrekturen

In der Realität kommen Daten oft verspätet oder korrigiert. Beispiele sind nachträglich ergänzte Kundendaten, korrigierte E-Mails oder rückwirkend gelieferte historische Datensätze.

Strategien sind ein Reprocessing-Fenster definieren, etwa 7 Tage rückwärts, Upserts (Insert oder Update) statt Inserts für korrigierbare Felder und ein Staging-Hash (Hash über die Rohzeile) zum Erkennen von Änderungen. Beispiel: Eine Adresse kommt 3 Tage später korrigiert, das Reprocessing-Fenster nimmt sie mit.

Ohne klare Regel läufst du in Endlosschleifen: jeder Run schreibt andere Daten, ohne dass du den Ursprung kennst.

Qualitätskennzahlen als KPI

Datenqualität wird erst steuerbar, wenn du Kennzahlen hast. Beispiele:

  • Reject-Rate = rejects / input
  • Duplicate-Rate = duplicateRows / input
  • Missing-Ref-Rate = missingRefs / input

Damit kannst du Trends erkennen. Beispiel: Heute doppelt so viele Rejects ist ein operatives Signal und gehört ins Monitoring.

Reconciliation: Zahlen müssen passen

Ein Batch ist fachlich nur korrekt, wenn sich die Zahlen erklären lassen. Reconciliation heißt: Zähler werden gegeneinander abgeglichen. Input-Count muss dem Read-Count entsprechen, Output-Count dem Write-Count, und Rejected/Skipped müssen dokumentiert sein.

Typischer Audit-Satz für einen Run:

input=100000, written=99500, skipped=500, failed=0

Diese Kennzahlen liefert Spring Batch automatisch über die StepExecution-Zähler: getReadCount(), getWriteCount(), getSkipCount() und getCommitCount(). Du kannst sie z. B. in einem StepExecutionListener auslesen und loggen oder an ein Monitoring-System senden. Einsteiger-Tipp: Wenn readCount und input nicht zueinander passen, stimmt der Importpfad nicht.

Artefakt: Datenqualitäts-Checkliste

Minimal-Checkliste für unseren Import:

  • [ ] Pflichtfelder geprüft (customer_id, email)
  • [ ] Datumsfelder validiert (ISO, keine Zukunftsdaten)
  • [ ] Dedupe-Regel definiert (customer_id eindeutig)
  • [ ] Referenzen geprüft (country_code bekannt)
  • [ ] Staging-Rohdaten gespeichert
  • [ ] Reconciliation-Zahlen dokumentiert
  • [ ] Late-Data-Strategie festgelegt

Anti-Patterns

Direkt in Zieltabellen schreiben verhindert Auditbarkeit. Duplikate still überschreiben bedeutet Datenverlust ohne Nachweis. Keine Reconciliation macht Erfolg nicht belegbar. Late Data ignorieren führt zu inkonsistenten Reports.

Zusätzlich riskant: DB-Reader ohne Snapshot/Cutoff machen Restarts nicht deterministisch.

Kurzfazit

Datenqualität ist Betriebsarbeit, nicht nur Validierung. Staging und Reconciliation machen Qualität messbar. Ohne Regeln für Duplikate und Late Data wird jeder Run unsicher.

Im nächsten Teil geht es um Performance-Grundlagen: Chunk-Größe, Fetch-Size und Batch-Writes und wie du Engpässe systematisch findest.

Alle Teile der Serie: Serie: Spring Batch

Mehr Beiträge aus dem Blog.