Modul 22 · Migration Deep Dive · Stufe 4 Daten und Transaktionen

Spring JDBC

Statement, ResultSet und manuelles Mapping wird nachvollziehbar in JdbcClient und RowMapper überführt. Die Akte zeigt nicht nur das Ziel, sondern die tatsächlichen Dateien, APIs, Dependencies, Codebelege, Tests, Risiken und Cutover-Schritte.

DAORepositoryRow Mapper
1 → 2Produktionsdateien
36 → 31Java-Zeilen
1 → 1Testdateien
1 / 2Dependencies entfernt / neu
NIEDRIGRisiko · Score 0

Was sich konkret ändert

DimensionLegacyModernMigrationskonsequenz
Programmiermodellimperativ / ohne Framework-Annotationenexplizite Java-AbstraktionenAnnotationen und Containerfunktionen werden nur dort eingesetzt, wo sie eine konkrete technische Verantwortung übernehmen.
Abhängigkeiten2 direkte Dependencies3 direkte Dependencies2 neu, 1 entfernt; Versionen und transitive Auswirkungen im erfolgreichen Online-Build prüfen.
Öffentliche API3 erkannte Methoden3 erkannte MethodenMethoden werden nach fachlicher Rolle gemappt; reine Bootstrap- und Framework-Methoden sind kein fachlicher Vertrag.
Datenmodellclass CustomerDaoclass CustomerRepository, record CustomerFeldnamen, IDs, Null-Semantik, Gleichheit und Serialisierungsform werden separat regressionstestet.
FehlerverhaltenLegacy-Exceptions und Rückgabewerteexplizitere Fach-/Framework-FehlerabbildungFehler dürfen nicht nur technisch übersetzt werden; Status, Ursache, Retrybarkeit und Client-Vertrag müssen erhalten oder versioniert werden.
TestsBestands- und Golden-Master-TestsUnit-, Slice-, Contract- und IntegrationstestsDer Modern-Pfad wird zuerst gegen denselben fachlichen Vektor geprüft und danach um neue technische Risiken ergänzt.
BetriebLegacy-Start/Lifecyclemodernes Packaging, Health und externe KonfigurationMigration mit produktionsnahen Daten, Backups, Restore-Probe und Query-/Lock-Monitoring absichern.
RollbackLegacy-Artefakt bleibt unverändertModern-Artefakt getrennt deploybarKein Rollback über Datenverlust: Schema, Nachrichten und verschlüsselte Daten müssen rückwärtslesbar oder durch Dual-Read abgesichert sein.

Fachlicher Vertrag: unverändert zu erhalten

  • SQL, Parameterbindung und Row-Mapping bleiben fachlich identisch.
  • Connections und Statements werden vom Framework sicher verwaltet.
  • Transaktionen liegen außerhalb des Repositorys.

Hauptrisiko und Testfokus

SQL mapping, transaction and resource handling

row mapping, empty result, duplicate key and rollback tests

Die Modernisierung gilt erst als abgeschlossen, wenn der fachliche Vertrag automatisiert belegt ist.

Verbindliches Code- und Rollenmapping

Die Zuordnung ist semantisch: Eine Legacy-Klasse kann in mehrere moderne Rollen zerlegt werden.

Legacy-Rolle / DateiModern-Rolle / DateiBedeutung
CustomerDao.javaCustomerRepository.java + Customer.javaManuelles JDBC wird JdbcClient Repository plus Row Mapping.

Legacy-Quellinventar

DateiTypAnnotationenöffentliche APIPatternZeilen
CustomerDao.javaclass CustomerDaovoid init()
void save(long id, String name)
Optional<String> findName(long id)
DAO36

Modern-Quellinventar

DateiTypAnnotationenöffentliche APIPatternZeilen
Customer.javarecord Customer4
CustomerRepository.javaclass CustomerRepositoryvoid init()
void save(Customer c)
Optional<Customer> find(long id)
Repository + Row Mapper27

Dependency- und Laufzeitmigration

StatusDependencyVersionScopePrüfung
ENTFERNTorg.junit.jupiter:junit-jupiterBOM/ParenttestLegacy-Laufzeit entfällt oder wird durch Plattform/BOM ersetzt.
NEUorg.springframework.boot:spring-boot-starter-jdbcBOM/ParentcompileNeue Laufzeit-/Testabhängigkeit; transitiv, lizenz- und security-seitig prüfen.
NEUorg.springframework.boot:spring-boot-starter-testBOM/ParenttestNeue Laufzeit-/Testabhängigkeit; transitiv, lizenz- und security-seitig prüfen.
BEIBEHALTENcom.h2database:h2BOM/Parent → BOM/Parentcompile → compileGemeinsame Dependency; Version und Scope im effektiven POM prüfen.
Direkte POM-Daten ersetzen keinen erfolgreichen Online-Build mit transitiver SBOM- und CVE-Prüfung.

Vorher-/Nachher-Codebelege

Die folgenden Ausschnitte stammen direkt aus den enthaltenen Projekten. Dadurch ist sichtbar, welche Verantwortung tatsächlich verschoben wurde.

Legacy
CustomerDao.java
Modern
CustomerRepository.java + Customer.java

Migrationsbedeutung: Manuelles JDBC wird JdbcClient Repository plus Row Mapping.

Legacy-Code

projects/22-spring-jdbc/legacy/src/main/java/at/aydin/lab/jdbc/legacy/CustomerDao.java

package at.aydin.lab.jdbc.legacy;

import java.sql.*;
import java.util.*;

// Design Pattern: DAO
// Zweck: Kapselt Statement-, ResultSet- und Mapping-Boilerplate.
public final class CustomerDao {
    private final Connection connection;
    public CustomerDao(Connection connection) {
        this.connection = connection;
    }

    public void init() throws SQLException {
        try (Statement s = connection.createStatement()) {
            s.execute("create table if not exists customer(id bigint primary key,name varchar(100))");
        }
    }

    public void save(long id, String name) throws SQLException {
        try (PreparedStatement p = connection.prepareStatement("merge into customer key(id) values(?,?)")) {
            p.setLong(1, id);
            p.setString(2, name);
            p.executeUpdate();
        }
    }

    public Optional<String> findName(long id) throws SQLException {
        try (PreparedStatement p = connection.prepareStatement("select name from customer where id=?")) {
            p.setLong(1, id);
            try (ResultSet r = p.executeQuery()) {
                return r.next() ? Optional.of(r.getString(1)) : Optional.empty();
            }
        }
    }
}

Modern-Code

projects/22-spring-jdbc/modern/src/main/java/at/aydin/lab/jdbc/modern/CustomerRepository.java

package at.aydin.lab.jdbc.modern;

import org.springframework.jdbc.core.simple.JdbcClient;
import java.util.*;

// Design Pattern: Repository + Row Mapper
// Zweck: SQL bleibt explizit, Infrastruktur-Boilerplate wird vom JdbcClient übernommen.
public final class CustomerRepository {
    private final JdbcClient jdbc;
    public CustomerRepository(JdbcClient jdbc) {
        this.jdbc = jdbc;
    }

    public void init() {
        jdbc.sql("create table if not exists customer(id bigint primary key,name varchar(100))").update();
    }

    public void save(Customer c) {
        jdbc.sql("merge into customer key(id) values(:id,:name)").param("id", c.id()).param("name", c.name())
                .update();
    }

    public Optional<Customer> find(long id) {
        return jdbc.sql("select id,name from customer where id=:id").param("id", id).query((rs, row) -> new Customer(rs.getLong("id"),
            rs.getString("name"))).optional();
    }
}

Modern-Code

projects/22-spring-jdbc/modern/src/main/java/at/aydin/lab/jdbc/modern/Customer.java

package at.aydin.lab.jdbc.modern;

public record Customer(long id, String name) {
}

Umsetzungsplan mit Qualitäts-Gates

  1. Arbeitspaket 1
    CustomerDao-SQL und Mapping mit Testdaten fixieren. Nachweis: Commit/PR, automatisierter Test und aktualisierte Betriebsdokumentation.
  2. Arbeitspaket 2
    Customer als stabiles Ergebnisobjekt definieren. Nachweis: Commit/PR, automatisierter Test und aktualisierte Betriebsdokumentation.
  3. Arbeitspaket 3
    CustomerRepository mit JdbcClient und parametrierten SQLs implementieren. Nachweis: Commit/PR, automatisierter Test und aktualisierte Betriebsdokumentation.
  4. Arbeitspaket 4
    Empty/Multiple-Result-Verhalten explizit abbilden. Nachweis: Commit/PR, automatisierter Test und aktualisierte Betriebsdokumentation.
  5. Arbeitspaket 5
    Duplicate-Key- und Constraint-Fehler übersetzen. Nachweis: Commit/PR, automatisierter Test und aktualisierte Betriebsdokumentation.
  6. Arbeitspaket 6
    DAO nach Integrations- und Rollbacktests entfernen. Nachweis: Commit/PR, automatisierter Test und aktualisierte Betriebsdokumentation.

Konkreter Test- und Abnahmekatalog

IDEbenePrüfungerforderlicher Nachweis
22-SPRING-JDBC-A01Integration/ContractKeine SQL-Konkatenation mit Nutzereingaben.Automatisierter Test und CI-Protokoll
22-SPRING-JDBC-A02Integration/ContractRow-Mapping deckt Null-/Typfälle ab.Automatisierter Test und CI-Protokoll
22-SPRING-JDBC-A03Integration/ContractLeere Ergebnisse haben definierte Semantik.Automatisierter Test und CI-Protokoll
22-SPRING-JDBC-A04Integration/ContractConstraint-Fehler sind stabil übersetzt.Automatisierter Test und CI-Protokoll
22-SPRING-JDBC-A05Integration/ContractRepository beteiligt sich korrekt an Service-Transaktionen.Automatisierter Test und CI-Protokoll
22-SPRING-JDBC-T01UnitFachlogik ohne Container oder externen Dienst testen.Unit-Test
22-SPRING-JDBC-T02RegressionLegacy- und Modern-Ergebnis für denselben Golden-Master-Vektor vergleichen.Vergleichsreport
22-SPRING-JDBC-T03NegativeFehlerhafte, leere und grenzwertige Eingaben prüfen.Negativtest
22-SPRING-JDBC-T04OperationsStart, Health, Shutdown und Konfigurationsfehler prüfen.Deployment-/Startprotokoll
22-SPRING-JDBC-T05DatabaseRollback, Constraints, Locking und Schema-Kompatibilität mit produktionsnahen Daten prüfen.DB-Integrationstest
22-SPRING-JDBC-F01Fokusrow mapping, empty result, duplicate key and rollback testsModulspezifischer Testreport

Risikoregister des Moduls

RisikoAuswirkungGegenmaßnahmeGate
SQL mapping, transaction and resource handlingNIEDRIGrow mapping, empty result, duplicate key and rollback testsvor Cutover
Neue Framework-/Library-LaufzeitabhängigkeitenMITTELSBOM, Lizenz-, CVE- und transitive Dependency-Prüfung im Online-Buildvor Release
Legacy-Verhalten war implizit an entfernte Library gekoppeltMITTELContract-/Golden-Master-Tests und gezielte Fehlerpfadevor Abschaltung

Konfiguration und Ressourcen

Keine zusätzlichen Ressourcen.

Rollback und Koexistenz

Beide Datenadapter können hinter einem Repository-Port laufen; nur einer wird pro Use Case aktiviert.

Abbruchkriterien

  • Fachlicher Golden-Master weicht ab.
  • Daten-, Nachrichten- oder API-Kompatibilität ist ungeklärt.
  • Fehlerquote, Latenz oder Ressourcenverbrauch überschreiten das vereinbarte Limit.
  • Monitoring oder Rückfallpfad ist nicht funktionsfähig.

Definition of Done

Direkte Arbeitslinks

⌂ Cockpit