555 Stimmen

Spring @Transactional - Isolierung, Vermehrung

Kann jemand erklären, was Isolierung & Ausbreitung Parameter sind für in der @Transactional Annotation anhand eines realen Beispiels?

Vor allem, wann und warum ich die Standardwerte ändern sollte.

545voto

Johan Sjöberg Punkte 45671

Eine gute Frage, die allerdings nicht leicht zu beantworten ist.

Ausbreitung

Legt fest, wie sich Transaktionen zueinander verhalten. Übliche Optionen:

  • REQUIRED : Der Code wird immer in einer Transaktion ausgeführt. Erzeugt eine neue Transaktion oder verwendet eine wieder, falls vorhanden.
  • REQUIRES_NEW : Der Code wird immer in einer neuen Transaktion ausgeführt. Unterbricht die aktuelle Transaktion, falls eine solche existiert.

Der Standardwert für @Transactional es REQUIRED und das ist oft das, was Sie wollen.

Isolierung

Definiert den Datenvertrag zwischen Transaktionen.

  • ISOLATION_READ_UNCOMMITTED : Erlaubt schmutziges Lesen.
  • ISOLATION_READ_COMMITTED : Erlaubt keine unsauberen Lesevorgänge.
  • ISOLATION_REPEATABLE_READ : Wenn eine Zeile zweimal in derselben Transaktion gelesen wird, ist das Ergebnis immer dasselbe.
  • ISOLATION_SERIALIZABLE : Führt alle Transaktionen in einer Reihenfolge aus.

Die verschiedenen Ebenen haben unterschiedliche Leistungsmerkmale in einer Multithreading-Anwendung. Ich denke, wenn Sie die schmutzige Lektüre Konzept können Sie eine gute Option auswählen.

Die Standardwerte können je nach Datenbank variieren. Zum Beispiel für MariaDB es ist REPEATABLE READ .


Beispiel für das Auftreten eines unsauberen Lesevorgangs:

  thread 1   thread 2      
      |         |
    write(x)    |
      |         |
      |        read(x)
      |         |
    rollback    |
      v         v 
           value (x) is now dirty (incorrect)

Eine vernünftige Vorgabe (wenn man sie denn einfordern kann) könnte also sein ISOLATION_READ_COMMITTED die nur das Lesen von Werten zulässt, die bereits von anderen laufenden Transaktionen übertragen wurden, in Kombination mit einem Propagierungsgrad von REQUIRED . Dann können Sie von dort aus arbeiten, wenn Ihre Anwendung andere Anforderungen hat.


Ein praktisches Beispiel, bei dem immer eine neue Transaktion erstellt wird, wenn man die provideService Routine und beim Verlassen abgeschlossen:

public class FooService {
    private Repository repo1;
    private Repository repo2;

    @Transactional(propagation=Propagation.REQUIRES_NEW)
    public void provideService() {
        repo1.retrieveFoo();
        repo2.retrieveFoo();
    }
}

Hätten wir stattdessen die REQUIRED die Transaktion würde offen bleiben wenn die Transaktion beim Eintritt in die Routine bereits geöffnet war. Beachten Sie auch, dass das Ergebnis einer rollback kann unterschiedlich sein, da mehrere Ausführungen an derselben Transaktion beteiligt sein können.


Wir können das Verhalten leicht mit einem Test überprüfen und sehen, wie sich die Ergebnisse je nach Ausbreitungsgrad unterscheiden:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:/fooService.xml")
public class FooServiceTests {

    private @Autowired TransactionManager transactionManager;
    private @Autowired FooService fooService;

    @Test
    public void testProvideService() {
        TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
        fooService.provideService();
        transactionManager.rollback(status);
        // assert repository values are unchanged ... 
}

Mit einem Ausbreitungsgrad von

  • REQUIRES_NEW : Wir würden erwarten fooService.provideService() war PAS zurückgenommen, da sie eine eigene Untertransaktion erstellt hat.

  • REQUIRED Wie zu erwarten war, wurde alles zurückgesetzt und der Sicherungsspeicher blieb unverändert.

395voto

abishkar bhattarai Punkte 7113

PROPAGATION_REQUIRED = 0 Wenn DataSourceTransactionObject T1 bereits für Methode M1 gestartet ist. Wenn für eine andere Methode M2 ein Transaktionsobjekt benötigt wird, wird kein neues Transaktionsobjekt angelegt. Für M2 wird dasselbe Objekt T1 verwendet.

PROPAGATION_MANDATORY = 2 ; Methode muss innerhalb einer Transaktion ablaufen. Wenn keine Transaktion vorhanden ist, wird eine Ausnahme ausgelöst.

PROPAGATION_REQUIRES_NEW = 3 Wenn das DataSourceTransactionObject T1 für die Methode M1 bereits gestartet ist und diese in Bearbeitung ist (Ausführung der Methode M1). Wenn die Ausführung einer anderen Methode M2 beginnt, wird T1 für die Dauer der Methode M2 mit einem neuen DataSourceTransactionObject T2 für M2 unterbrochen. M2 wird in seinem eigenen Transaktionskontext ausgeführt.

PROPAGATION_NOT_SUPPORTED = 4 Wenn DataSourceTransactionObject T1 bereits für Methode M1 gestartet ist. Wenn gleichzeitig eine andere Methode M2 ausgeführt wird. Dann sollte M2 nicht im Transaktionskontext laufen. T1 wird ausgesetzt, bis M2 beendet ist.

PROPAGATION_NEVER = 5 Keine der Methoden läuft im Transaktionskontext.


Eine Isolationsebene: Es geht darum, wie sehr eine Transaktion durch die Aktivitäten anderer gleichzeitiger Transaktionen beeinflusst werden kann. Es unterstützt die Konsistenz, indem es die Daten über viele Tabellen hinweg in einem konsistenten Zustand belässt. Sie beinhaltet das Sperren von Zeilen und/oder Tabellen in einer Datenbank.

Das Problem mit Mehrfachtransaktionen

Szenario 1 . Wenn die Transaktion T1 Daten aus der Tabelle A1 liest, die von einer anderen konkurrierenden Transaktion T2 geschrieben wurden. Wenn T2 auf dem Weg dorthin einen Rollback durchführt, sind die von T1 erhaltenen Daten ungültig. Z.B. a=2 sind die Originaldaten. Wenn T1 a=1 liest, das von T2 geschrieben wurde. Wenn T2 ein Rollback durchführt, wird a=1 zu a=2 in der DB zurückgesetzt. Aber jetzt hat T1 a=1, aber in der DB-Tabelle ist es in a=2 geändert.

Szenario2 . Wenn die Transaktion T1 Daten aus der Tabelle A1 liest. Wenn eine andere gleichzeitige Transaktion (T2) Daten in Tabelle A1 aktualisiert. Die Daten, die T1 gelesen hat, sind dann anders als die Tabelle A1. Denn T2 hat die Daten in Tabelle A1 aktualisiert. Wenn T1 z.B. a=1 gelesen und T2 a=2 aktualisiert hat. Dann ist a!=b.

Szenario 3 . Wenn die Transaktion T1 Daten aus der Tabelle A1 mit einer bestimmten Anzahl von Zeilen liest. Wenn eine andere gleichzeitige Transaktion (T2) weitere Zeilen in die Tabelle A1 einfügt. Die Anzahl der von T1 gelesenen Zeilen unterscheidet sich von der Anzahl der Zeilen in Tabelle A1.

Szenario 1 wird als Schmutzig liest.

Szenario 2 wird als Nicht wiederholbare Lektüre.

Szenario 3 wird als Das Phantom liest.

Der Isolationsgrad ist also das Ausmaß, in dem Szenario 1, Szenario 2, Szenario 3 verhindert werden kann. Sie können eine vollständige Isolationsebene erreichen, indem Sie Sperren implementieren. Das bedeutet, dass das gleichzeitige Lesen und Schreiben der gleichen Daten verhindert wird. Dies beeinträchtigt jedoch die Leistung. Der Grad der Isolierung hängt von Anwendung zu Anwendung ab, wie viel Isolierung erforderlich ist.

ISOLATION_READ_UNCOMMITTED : Ermöglicht das Lesen von Änderungen, die noch nicht übertragen wurden. Sie leiden unter Szenario 1, Szenario 2 und Szenario 3.

ISOLATION_READ_COMMITTED : Erlaubt das Lesen von gleichzeitigen Transaktionen, die bereits bestätigt wurden. Es kann unter Szenario 2 und Szenario 3 leiden. Denn andere Transaktionen können die Daten aktualisieren.

ISOLATION_WIEDERHOLBAR_LESEN : Das mehrfache Lesen desselben Feldes führt zu denselben Ergebnissen, bis es selbst geändert wird. Es kann unter Szenario 3 leiden. Weil andere Transaktionen die Daten einfügen können.

ISOLIERUNG_SERIALISIERBAR : Szenario 1, Szenario 2 und Szenario 3 treten nie ein. Es handelt sich um eine vollständige Isolierung. Es beinhaltet vollständiges Sperren. Es beeinträchtigt die Leistung wegen der Sperrung.

Sie können mit testen:

public class TransactionBehaviour {
   // set is either using xml Or annotation
    DataSourceTransactionManager manager=new DataSourceTransactionManager();
    SimpleTransactionStatus status=new SimpleTransactionStatus();
   ;

    public void beginTransaction()
    {
        DefaultTransactionDefinition Def = new DefaultTransactionDefinition();
        // overwrite default PROPAGATION_REQUIRED and ISOLATION_DEFAULT
        // set is either using xml Or annotation
        manager.setPropagationBehavior(XX);
        manager.setIsolationLevelName(XX);

        status = manager.getTransaction(Def);

    }

    public void commitTransaction()
    {

            if(status.isCompleted()){
                manager.commit(status);
        } 
    }

    public void rollbackTransaction()
    {

            if(!status.isCompleted()){
                manager.rollback(status);
        }
    }
    Main method{
        beginTransaction()
        M1();
        If error(){
            rollbackTransaction()
        }
         commitTransaction();
    }

}

Sie können das Ergebnis mit verschiedenen Werten für Isolation und Propagation debuggen und sehen.

138voto

ye9ane Punkte 1939

Ausreichende Erläuterungen zu den einzelnen Parametern finden sich in anderen Antworten; Sie haben jedoch nach einem Beispiel aus der Praxis gefragt, und hier ist eines, das den Zweck der verschiedenen Parameter verdeutlicht Ausbreitung Optionen:

Angenommen, Sie sind verantwortlich für die Implementierung eines Anmeldedienst in der eine Bestätigungs-E-Mail an den Benutzer gesendet wird. Sie haben zwei Serviceobjekte entwickelt, eines für Einschreibung den Nutzer und eine für Senden E-Mails, wobei letztere innerhalb der ersten aufgerufen wird. Zum Beispiel etwas wie dieses:

/* Sign Up service */
@Service
@Transactional(Propagation=REQUIRED)
class SignUpService{
 ...
 void SignUp(User user){
    ...
    emailService.sendMail(User);
 }
}

/* E-Mail Service */
@Service
@Transactional(Propagation=REQUIRES_NEW)
class EmailService{
 ...
 void sendMail(User user){
  try{
     ... // Trying to send the e-mail
  }catch( Exception)
 }
}

Sie haben vielleicht bemerkt, dass der zweite Dienst vom Typ Vermehrung ist REQUIRES_NEU und darüber hinaus besteht die Möglichkeit, dass eine Ausnahme ausgelöst wird (SMTP-Server ausgefallen, ungültige E-Mail oder andere Gründe). Wahrscheinlich wollen Sie nicht, dass der gesamte Prozess rückgängig gemacht wird, wie z. B. das Entfernen der Benutzerdaten aus einer Datenbank oder andere Dinge; daher rufen Sie den zweiten Dienst in einer separaten Transaktion auf.

Zurück zu unserem Beispiel. Diesmal geht es Ihnen um die Sicherheit der Datenbank, also definieren Sie Ihre DAO-Klassen auf diese Weise:

/* User DAO */
@Transactional(Propagation=MANDATORY)
class UserDAO{
 // some CRUD methods
}

Das bedeutet, dass wir jedes Mal, wenn ein DAO-Objekt und damit ein potenzieller Zugriff auf die DB erstellt wird, sicherstellen müssen, dass der Aufruf von einem unserer Dienste aus erfolgt ist, was bedeutet, dass eine aktive Transaktion vorhanden sein sollte; andernfalls tritt eine Ausnahme auf. Daher ist die Propagierung vom Typ MANDATISCH .

69voto

reos Punkte 8158

Isolationsgrad definiert, wie sich die von einer Transaktion an einem Datenspeicher vorgenommenen Änderungen auf andere, gleichzeitig stattfindende Transaktionen auswirken und wie und wann die geänderten Daten für andere Transaktionen verfügbar werden. Wenn wir eine Transaktion mit dem Spring-Framework definieren, können wir auch konfigurieren, in welcher Isolationsebene dieselbe Transaktion ausgeführt werden soll.

@Transactional(isolation=Isolation.READ_COMMITTED)
public void someTransactionalMethod(Object obj) {

}

Die Isolationsstufe READ_UNCOMMITTED besagt, dass eine Transaktion Daten lesen darf, die von anderen Transaktionen noch nicht bestätigt wurden.

Die Isolationsstufe READ_COMMITTED besagt, dass eine Transaktion keine Daten lesen kann, die noch nicht von anderen Transaktionen bestätigt wurden.

Die Isolationsebene REPEATABLE_READ besagt, dass, wenn eine Transaktion einen Datensatz mehrmals aus der Datenbank liest, das Ergebnis all dieser Lesevorgänge immer dasselbe sein muss.

Die Isolationsebene SERIALIZABLE ist die restriktivste aller Isolationsebenen. Transaktionen werden mit Sperren auf allen Ebenen (Lese-, Bereichs- und Schreibsperren) ausgeführt, so dass sie so aussehen, als ob sie in serieller Form ausgeführt würden.

Ausbreitung ist die Fähigkeit zu entscheiden, wie die Geschäftsmethoden in logischen oder physischen Transaktionen gekapselt werden sollen.

Das Spring REQUIRED-Verhalten bedeutet, dass dieselbe Transaktion verwendet wird, wenn es im aktuellen Ausführungskontext der Bean-Methode bereits eine geöffnete Transaktion gibt.

Das Verhalten REQUIRES_NEW bedeutet, dass der Container immer eine neue physische Transaktion erstellt.

Das NESTED-Verhalten sorgt dafür, dass verschachtelte Spring-Transaktionen dieselbe physische Transaktion verwenden, setzt aber Savepoints zwischen den verschachtelten Aufrufen, so dass innere Transaktionen auch unabhängig von äußeren Transaktionen rollbackfähig sind.

Das MANDATORY-Verhalten besagt, dass eine bereits geöffnete Transaktion bereits existieren muss. Ist dies nicht der Fall, wird vom Container eine Ausnahme ausgelöst.

Das NEVER-Verhalten besagt, dass eine bereits geöffnete Transaktion nicht bereits existieren darf. Wenn eine Transaktion existiert, wird vom Container eine Ausnahme ausgelöst.

Das NOT_SUPPORTED-Verhalten wird außerhalb des Bereichs einer Transaktion ausgeführt. Wenn eine geöffnete Transaktion bereits existiert, wird sie angehalten.

Das SUPPORTS-Verhalten wird im Rahmen einer Transaktion ausgeführt, wenn bereits eine geöffnete Transaktion existiert. Gibt es keine bereits geöffnete Transaktion, wird die Methode trotzdem ausgeführt, allerdings auf eine nicht-transaktionale Weise.

43voto

Premraj Punkte 65511

A Transaktion stellt eine Arbeitseinheit mit einer Datenbank dar. Das Transaktionsverhalten bei mehreren Diensten, die ihre eigenen txns (oder keine txn) haben, ist bekannt als Ausbreitung von Vorgängen . Transaktionsisolierung definiert den Datenbankzustand, wenn zwei Transaktionen gleichzeitig auf dieselbe Datenbankeinheit einwirken.

Im Frühling TransactionDefinition Schnittstelle, die Spring-konforme Transaktionseigenschaften definiert. @Transactional beschreibt Transaktionsattribute zu einer Methode oder Klasse.

@Autowired
private TestDAO testDAO;

@Transactional(propagation=TransactionDefinition.PROPAGATION_REQUIRED,isolation=TransactionDefinition.ISOLATION_READ_UNCOMMITTED)
public void someTransactionalMethod(User user) {

  // Interact with testDAO

}

Vermehrung (Vermehrung) : wird für Beziehungen zwischen Transaktionen verwendet. (analog zur Inter-Thread-Kommunikation in Java)

+-------+---------------------------+------------------------------------------------------------------------------------------------------+
| value |        Propagation        |                                             Description                                              |
+-------+---------------------------+------------------------------------------------------------------------------------------------------+
|    -1 | TIMEOUT_DEFAULT           | Use the default timeout of the underlying transaction system, or none if timeouts are not supported. |
|     0 | PROPAGATION_REQUIRED      | Support a current transaction; create a new one if none exists.                                      |
|     1 | PROPAGATION_SUPPORTS      | Support a current transaction; execute non-transactionally if none exists.                           |
|     2 | PROPAGATION_MANDATORY     | Support a current transaction; throw an exception if no current transaction exists.                  |
|     3 | PROPAGATION_REQUIRES_NEW  | Create a new transaction, suspending the current transaction if one exists.                          |
|     4 | PROPAGATION_NOT_SUPPORTED | Do not support a current transaction; rather always execute non-transactionally.                     |
|     5 | PROPAGATION_NEVER         | Do not support a current transaction; throw an exception if a current transaction exists.            |
|     6 | PROPAGATION_NESTED        | Execute within a nested transaction if a current transaction exists.                                 |
+-------+---------------------------+------------------------------------------------------------------------------------------------------+

Isolierung : Isolation ist eine der ACID-Eigenschaften (Atomicity, Consistency, Isolation, Durability) von Datenbanktransaktionen. Die Isolation bestimmt, wie die Integrität der Transaktion für andere Benutzer und Systeme sichtbar ist. Sie dient der Ressourcensperrung, d.h. der Gleichzeitigkeitskontrolle, die sicherstellt, dass nur eine Transaktion zu einem bestimmten Zeitpunkt auf die Ressource zugreifen kann.

Wahrnehmung sperren: Die Isolationsebene bestimmt die Dauer, für die Sperren gehalten werden.

+---------------------------+-------------------+-------------+-------------+------------------------+
| Isolation Level Mode      |  Read             |   Insert    |   Update    |       Lock Scope       |
+---------------------------+-------------------+-------------+-------------+------------------------+
| READ_UNCOMMITTED          |  uncommitted data | Allowed     | Allowed     | No Lock                |
| READ_COMMITTED (Default)  |   committed data  | Allowed     | Allowed     | Lock on Committed data |
| REPEATABLE_READ           |   committed data  | Allowed     | Not Allowed | Lock on block of table |
| SERIALIZABLE              |   committed data  | Not Allowed | Not Allowed | Lock on full table     |
+---------------------------+-------------------+-------------+-------------+------------------------+

Wahrnehmung lesen: die folgenden 3 Arten von Hauptproblemen auftreten:

  • Schmutzige Lektüre Liest unbestätigte Daten von einer anderen tx(Transaktion).
  • Nicht wiederholbare Lesungen : liest engagiert UPDATES von einer anderen tx.
  • Phantom liest : liest engagiert INSERTS und/oder DELETES von einem anderen tx

Das folgende Diagramm zeigt, welche Transaktionsisolationsebene welche Probleme der Gleichzeitigkeit löst:

+---------------------------+--------------+----------------------+----------------+
| Isolation Level Mode      |  Dirty reads | Non-repeatable reads | Phantoms reads |
+---------------------------+--------------+----------------------+----------------+
| READ_UNCOMMITTED          | X            | X                    | X           |
| READ_COMMITTED (Default)  | solves       | X                    | X           |
| REPEATABLE_READ           | solves       | solves               | X           |
| SERIALIZABLE              | solves       | solves               | solves      |
+---------------------------+--------------+----------------------+----------------+

für Beispiele

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X