Migration Deep Dive für 05 · Transaktionen öffnen →
⌂ ÜbersichtAlle Vergleiche
Modul 05 · 100 % Codeabdeckung

Transaktionen

Vollständiger Legacy-Modern-Vergleich aller Java-Klassen, Tests, Maven-POMs und relevanten Ressourcen dieses Moduls. Jede Datei ist genau einmal einer fachlich passenden Vergleichsgruppe zugeordnet.

4Legacy-Dateien
6Modern-Dateien
135 → 123Codezeilen
11/11vollständig erfasst

Fachliche Einordnung

Legacy

Manuelles JDBC Commit/Rollback

Die Service-Methode öffnet die Connection und steuert Commit, Rollback und Auto-Commit selbst.

Modern

Deklaratives @Transactional

Die Service-Methode beschreibt die Transaktionsgrenze deklarativ; das Repository übernimmt den Datenzugriff.

Vergleichsfokus: Alle Dateien werden nach technischer Rolle und fachlicher Verantwortung gruppiert.
Wichtige Abgrenzung: One-to-many-Änderungen werden als Gruppe dargestellt; eine künstliche 1:1-Zuordnung wird vermieden.

Vollständige Abdeckungsmatrix

Die Ähnlichkeit ist eine technische Orientierung auf normalisiertem Quelltext. Sie ersetzt keine fachliche Bewertung.

VergleichsgruppeLegacy-DateienModern-DateienLegacy-ZeilenModern-ZeilenÄhnlichkeit
Build-Konfiguration11354356%
Bootstrap und Konfiguration12151330%
Transfer-Use-Case und Test22854416%
Persistenzabstraktion010230%

Gemeinsame Modulstruktur

Das Pair-POM bindet die Legacy- und Modern-Submodule zusammen und gehört deshalb ebenfalls zur vollständigen Codeabdeckung.

Gemeinsam · 19 Zeilenpom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>at.aydin.academy</groupId>
        <artifactId>java-modernization-deep-dive</artifactId>
        <version>1.0.0</version>
        <relativePath>../../pom.xml</relativePath>
    </parent>
    <artifactId>05transactions-pair</artifactId>
    <packaging>pom</packaging>
    <name>Transaktionen: Legacy und Modern</name>
    <modules>
        <module>legacy</module>
        <module>modern</module>
    </modules>
</project>

Alle semantischen Codevergleiche

01Build-KonfigurationDirektvergleich · Legacy 35 / Modern 43 Zeilen · Ähnlichkeit 56%

Transaktions- und Persistenzabhängigkeiten werden verglichen.

Legacy-DateienModern-DateienEinordnung
pom.xmlpom.xmlDirektvergleich
Semantische Ähnlichkeit: 56%

Legacy

Legacy · 35 Zeilenlegacy/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>at.aydin.academy</groupId>
        <artifactId>05transactions-pair</artifactId>
        <version>1.0.0</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
    <artifactId>transactions-legacy</artifactId>
    <packaging>jar</packaging>
    <name>Transactions Legacy (JDBC)</name>
    <dependencies>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
            </plugin>

        </plugins>
    </build>
</project>

Modern

Modern · 43 Zeilenmodern/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>at.aydin.academy</groupId>
        <artifactId>05transactions-pair</artifactId>
        <version>1.0.0</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
    <artifactId>transactions-modern</artifactId>
    <packaging>jar</packaging>
    <name>Transactions Modern (Spring)</name>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
02Bootstrap und KonfigurationDirektvergleich · Legacy 15 / Modern 13 Zeilen · Ähnlichkeit 30%

Manuelles Datenbanksetup wird durch Boot-Konfiguration ersetzt.

Legacy-DateienModern-DateienEinordnung
TransactionsLegacyApplication.javaTransactionsModernApplication.java
application.properties
Direktvergleich
Semantische Ähnlichkeit: 30%

Legacy

package at.aydin.lab.transactions.legacy;

import java.math.BigDecimal;

public final class TransactionsLegacyApplication {
    private TransactionsLegacyApplication() {
    }

    public static void main(String[] args) {
        LegacyTransferService service = new LegacyTransferService("jdbc:h2:mem:txlegacy;DB_CLOSE_DELAY=-1");
        service.transfer(1, 2, new BigDecimal("50.00"), false);
        System.out.println("Konto 1: " + service.balance(1));
        System.out.println("Konto 2: " + service.balance(2));
    }
}

Modern

package at.aydin.lab.transactions.modern;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class TransactionsModernApplication {
    public static void main(String[] args) {
        SpringApplication.run(TransactionsModernApplication.class, args);
    }
}
03Transfer-Use-Case und TestDirektvergleich · Legacy 85 / Modern 44 Zeilen · Ähnlichkeit 16%

Explizite JDBC-Transaktion wird mit deklarativer Transaktion verglichen.

Legacy-DateienModern-DateienEinordnung
LegacyTransferService.java
LegacyTransferServiceTest.java
TransferService.java
TransferServiceTest.java
Direktvergleich
Semantische Ähnlichkeit: 16%

Legacy

package at.aydin.lab.transactions.legacy;

import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

// Design Pattern: Transaction Script
// Zweck: Ein kompletter fachlicher Ablauf wird explizit in einer Methode transaktional ausgeführt.
public final class LegacyTransferService {
    private final String url;
    public LegacyTransferService(String url) {
        this.url = url;
        initialize();
    }

    private Connection connection() throws SQLException {
        return DriverManager.getConnection(url, "sa", "");
    }

    private void initialize() {
        try (Connection c = connection(); Statement s = c.createStatement()) {
            s.executeUpdate("create table if not exists account(id bigint primary key, balance decimal(15,2))");
            s.executeUpdate("merge into account key(id) values (1,1000.00),(2,200.00)");
        } catch (SQLException e) {
            throw new IllegalStateException(e);
        }
    }

    public void transfer(long from, long to, BigDecimal amount, boolean simulateFailure) {
        try (Connection c = connection()) {
            c.setAutoCommit(false);
            try {
                update(c, from, amount.negate());
                if (simulateFailure) throw new IllegalStateException("Simulierter Fehler");
                update(c, to, amount);
                c.commit();
            } catch (Exception e) {
                c.rollback();
                throw new IllegalStateException("Überweisung zurückgerollt", e);
            }
        } catch (SQLException e) {
            throw new IllegalStateException(e);
        }
    }

    private void update(Connection c, long id, BigDecimal delta) throws SQLException {
        try (PreparedStatement ps = c.prepareStatement("update account set balance=balance+? where id=?")) {
            ps.setBigDecimal(1, delta);
            ps.setLong(2, id);
            if (ps.executeUpdate() != 1) throw new SQLException("Konto fehlt: " + id);
        }
    }

    public BigDecimal balance(long id) {
        try (Connection c = connection(); PreparedStatement ps = c.prepareStatement("select balance from account where id=?")) {
            ps.setLong(1, id);
            try (ResultSet rs = ps.executeQuery()) {
                if (!rs.next()) throw new IllegalArgumentException();
                return rs.getBigDecimal(1);
            }
        } catch (SQLException e) {
            throw new IllegalStateException(e);
        }
    }
}
package at.aydin.lab.transactions.legacy;

import org.junit.jupiter.api.Test;
import java.math.BigDecimal;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

class LegacyTransferServiceTest {
    @Test
    void rollsBackBothUpdates() {
        LegacyTransferService service = new LegacyTransferService("jdbc:h2:mem:txrollback;DB_CLOSE_DELAY=-1");
        assertThrows(IllegalStateException.class, () -> service.transfer(1, 2, new BigDecimal("50.00"), true));
        assertEquals(new BigDecimal("1000.00"), service.balance(1));
        assertEquals(new BigDecimal("200.00"), service.balance(2));
    }
}

Modern

package at.aydin.lab.transactions.modern;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;

@Service
// Design Pattern: Service Layer + declarative Transaction Boundary
// Zweck: Rollback-Regeln werden vom Framework statt durch manuelles JDBC gesteuert.
public class TransferService {
    private final AccountRepository repository;
    public TransferService(AccountRepository repository) {
        this.repository = repository;
    }

    @Transactional
    public void transfer(long from, long to, BigDecimal amount, boolean simulateFailure) {
        repository.changeBalance(from, amount.negate());
        if (simulateFailure) throw new IllegalStateException("Simulierter Fehler");
        repository.changeBalance(to, amount);
    }
}
package at.aydin.lab.transactions.modern;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.math.BigDecimal;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

@SpringBootTest
class TransferServiceTest {
    @Autowired
    TransferService service;
    @Autowired
    AccountRepository repository;
    @Test
    void rollsBackOnRuntimeException() {
        assertThrows(IllegalStateException.class, () -> service.transfer(1, 2, new BigDecimal("50.00"), true));
        assertEquals(new BigDecimal("1000.00"), repository.balance(1));
        assertEquals(new BigDecimal("200.00"), repository.balance(2));
    }
}
04PersistenzabstraktionNeu in Modern · Legacy 0 / Modern 23 Zeilen · Ähnlichkeit 0%

Repository wird als neue, getrennte Datenzugriffsschicht eingeführt.

Legacy-DateienModern-DateienEinordnung
AccountRepository.javaNeu in Modern
Semantische Ähnlichkeit: 0%

Legacy

Kein Legacy-Gegenstück. Diese Verantwortung wurde neu eingeführt.

Modern

package at.aydin.lab.transactions.modern;

import org.springframework.jdbc.core.simple.JdbcClient;
import org.springframework.stereotype.Repository;
import java.math.BigDecimal;

@Repository
public class AccountRepository {
    private final JdbcClient jdbc;
    public AccountRepository(JdbcClient jdbc) {
        this.jdbc = jdbc;
    }

    public void changeBalance(long id, BigDecimal delta) {
        int count = jdbc.sql("update account set balance=balance+:delta where id=:id").param("delta", delta).param("id", id)
                .update();
        if (count != 1) throw new IllegalArgumentException("Konto fehlt: " + id);
    }

    public BigDecimal balance(long id) {
        return jdbc.sql("select balance from account where id=:id").param("id", id).query(BigDecimal.class).single();
    }
}
⌂ Cockpit