Die @Transactional-Annotation in einer Spring Boot-Anwendung spielt eine zentrale Rolle bei der Verwaltung von Transaktionen im Zusammenhang mit der Java Persistence API (JPA). Dieser Artikel wird sich ausführlich mit der Verwendung dieser Annotation in einer Spring Boot JPA-Anwendung befassen, insbesondere mit den verschiedenen Propagation-Varianten und Isolation-Levels, die sie bietet.

Einführung in @Transactional

Die @Transactional-Annotation wird in Spring verwendet, um Transaktionsverhalten für bestimmte Methoden zu definieren. In einer JPA-Anwendung kommt sie häufig zum Einsatz, um sicherzustellen, dass Operationen auf der Datenbank atomar, konsistent, isoliert und dauerhaft (ACID-Prinzipien) durchgeführt werden.

Grundlegende Verwendung

Um die @Transactional-Annotation zu verwenden, platziert man sie einfach über der Methode oder der Service-Klasse, die eine Transaktion benötigt. Hier ein einfaches Beispiel:

@Service
public class MyService {

    @Autowired
    private MyRepository myRepository;

    @Transactional
    public void performTransaction() {
        // Transaktionale Logik hier
        myRepository.save(entity);
        // Weitere Logik...
    }
}Code-Sprache: PHP (php)

In diesem Beispiel wird die performTransaction-Methode als Transaktion behandelt, und alle darin enthaltenen Operationen werden als Teil derselben Transaktion ausgeführt.

Propagation-Varianten

Die Propagation-Variante legt fest, wie sich eine Transaktion verhalten soll, wenn sie auf eine bereits laufende Transaktion trifft oder wenn keine vorhanden ist. In Spring gibt es mehrere Propagation-Varianten, die durch das Attribut propagation der @Transactional-Annotation gesteuert werden.

REQUIRED

@Transactional(propagation = Propagation.REQUIRED)
public void requiredPropagation() {
    // Transaktionale Logik hier
}Code-Sprache: JavaScript (javascript)

Die REQUIRED-Propagation gibt an, dass die Methode in einer vorhandenen Transaktion ausgeführt werden sollte, oder eine neue Transaktion startet, falls keine vorhanden ist. Dies ist die Standard-Propagation und wird häufig verwendet.

REQUIRES_NEW

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void requiresNewPropagation() {
    // Transaktionale Logik hier
}Code-Sprache: JavaScript (javascript)

Die REQUIRES_NEW-Propagation gibt an, dass die Methode immer in einer neuen Transaktion ausgeführt werden sollte. Wenn eine Transaktion bereits läuft, wird sie pausiert und eine neue gestartet.

NESTED

@Transactional(propagation = Propagation.NESTED)
public void nestedPropagation() {
    // Transaktionale Logik hier
}Code-Sprache: JavaScript (javascript)

Die NESTED-Propagation ist ähnlich wie REQUIRED, startet jedoch eine „verschachtelte“ Transaktion innerhalb der aktuellen Transaktion. Wenn die äußere Transaktion abgeschlossen wird, wird die innere Transaktion entweder committet oder zurückgerollt, abhängig von ihrem eigenen Status.

SUPPORTS

@Transactional(propagation = Propagation.SUPPORTS)
public void supportsPropagation() {
    // Transaktionale Logik hier
}Code-Sprache: JavaScript (javascript)

Die SUPPORTS-Propagation gibt an, dass die Methode in einer vorhandenen Transaktion ausgeführt werden sollte, aber keine neue gestartet werden sollte, wenn keine vorhanden ist.

NOT_SUPPORTED

@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void notSupportedPropagation() {
    // Transaktionale Logik hier
}Code-Sprache: JavaScript (javascript)

Die NOT_SUPPORTED-Propagation gibt an, dass die Methode außerhalb einer Transaktion ausgeführt werden sollte. Falls eine Transaktion bereits vorhanden ist, wird sie vorübergehend pausiert.

NEVER

@Transactional(propagation = Propagation.NEVER)
public void neverPropagation() {
    // Transaktionale Logik hier
}Code-Sprache: JavaScript (javascript)

Die NEVER-Propagation gibt an, dass die Methode außerhalb einer Transaktion ausgeführt werden sollte. Wenn eine Transaktion bereits läuft, wird eine Ausnahme ausgelöst.

Isolation-Levels

Das Isolation-Level einer Transaktion gibt an, wie die Transaktionsergebnisse in Bezug auf andere gleichzeitige Transaktionen behandelt werden. Spring unterstützt verschiedene Isolation-Levels, die mithilfe des Attributs isolation der @Transactional-Annotation festgelegt werden können.

DEFAULT

@Transactional(isolation = Isolation.DEFAULT)
public void defaultIsolation() {
    // Transaktionale Logik hier
}Code-Sprache: PHP (php)

Das DEFAULT-Isolation-Level verwendet den Standard-Isolationsgrad der zugrunde liegenden Datenbank. Dies ist oft READ_COMMITTED, was bedeutet, dass eine Transaktion nur auf bereits committete Daten anderer Transaktionen zugreifen kann.

READ_UNCOMMITTED

@Transactional(isolation = Isolation.READ_UNCOMMITTED)
public void readUncommittedIsolation() {
    // Transaktionale Logik hier
}Code-Sprache: JavaScript (javascript)

Das READ_UNCOMMITTED-Isolation-Level erlaubt einer Transaktion, auf noch nicht committete Änderungen anderer Transaktionen zuzugreifen. Dies birgt jedoch das Risiko von sogenannten „Dirty Reads“.

READ_COMMITTED

@Transactional(isolation = Isolation.READ_COMMITTED)
public void readCommittedIsolation() {
    // Transaktionale Logik hier
}Code-Sprache: JavaScript (javascript)

Das READ_COMMITTED-Isolation-Level ermöglicht einer Transaktion nur den Zugriff auf bereits committete Daten anderer Transaktionen. Dies minimiert das Risiko von „Dirty Reads“.

REPEATABLE_READ

@Transactional(isolation = Isolation.REPEATABLE_READ)
public void repeatableReadIsolation() {
    // Transaktionale Logik hier
}Code-Sprache: JavaScript (javascript)

Das REPEATABLE_READ-Isolation-Level stellt sicher, dass eine Transaktion auf dieselben Daten in derselben Reihenfolge zugreifen kann, unabhängig davon, ob andere Transaktionen in der Zwischenzeit Änderungen committen.

SERIALIZABLE

@Transactional(isolation = Isolation.SERIALIZABLE)
public void serializableIsolation() {
    // Transaktionale Logik hier
}Code-Sprache: JavaScript (javascript)

Das SERIALIZABLE-Isolation-Level ist das strengste Level, bei dem alle Transaktionen so abgewickelt werden, als ob sie nacheinander ausgeführt würden. Dies minimiert das Risiko von „Dirty Reads“, „Non-Repeatable Reads“ und „Phantom Reads“.

Schlussfolgerung

In diesem Artikel haben wir die @Transactional-Annotation in einer Spring Boot JPA-Anwendung eingehend betrachtet. Wir haben die verschiedenen Propagation-Varianten und Isolation-Levels erklärt, die diese Annotation bietet, und wie sie dazu beitragen, die Integrität und Konsistenz von Datenbanktransaktionen zu gewährleisten.

Es ist wichtig, die richtigen Propagation-Varianten und Isolation-Levels basierend auf den Anforderungen der Anwendung zu wählen. Die sorgfältige Verwendung dieser Annotation ermöglicht eine präzise Steuerung des Transaktionsverhaltens und trägt dazu bei, dass Datenbankoperationen in einer Spring Boot JPA-Anwendung effizient und zuverlässig abgewickelt werden.