JPA TX
Last updated
Was this helpful?
Last updated
Was this helpful?
http://piotrnowicki.com/2012/11/types-of-entitymanagers-application-managed-entitymanager/
JPA kennt drei Formen von Entity Managern (EM):
Java-EE-Ansatz: Container Managed (CM) EM - basieren auf JTA Transaktionen (die es nicht im Java SE gibt)
transaction scoped CM EM
extended scoped CM EM
Application Managed (AM) EM
JPA kennt folgende Transaction Management Typen:
RESOURCE LOCAL
hier übernimmt i. a. der JDBC-Datenbanktreiber das Transaktionmanagement
man ist damit beschränkt auf EINE transaktionale Ressource (i. a. die Datenbank-Connection)
ein evtl. vorhandener Application-Server kümmern sich nicht um die Transaktionsinfrastruktur ... die Applikation ist selbst dafür verantworlich
JTA (= GLOBAL)
hier übernimmt der JEE Container das Transaktionmanagement
hier kann man mehrere transaktionale Ressourcen (Database Connection, JMS Connection, ...) an eine Transaktion binden, um so beispielsweise über das XA-Protokoll eine verteilte Transaktion abzubilden.
Das ist die am häufigsten anzutreffende Form von Entity Managern. Diese EM sind stateless und dadurch threadsafe - jeder Methodenaufruf läuft in einer eigenen Transaktion und am Ende der Methode wird die Transaktion beendet (commit/rollback). Aber der (veränderte) Zustand der Entitäten muß natürlich irgendwo gespeichert werden ... er wird ja i. a. nicht sofort für alle sichtbar in die Datenbank geschrieben. Der Status liegt im PersistenceContext
, der an der JTA-Transaktion hängt (ACHTUNG: solche EntityManager benötigen JTA-Transactions!!!).
Die Unit-of-Work der Transaktion wird in der JTA-Transaktion gehalten - deshalb kann der EntityManager
bzw. PersistenceContext
auch in @Stateless
Beans wiederverwendet werden. Die Separierung parallel laufender Conversations erfolgt also über die JTA-Transaktion (die vermutlich über ThreadLocals abgebildet ist).
Beim committen der Transaktion wird der Zustand des PersistenceContext
persistiert und der PersistenceContext
wird nicht mehr benötigt.
Während der Transaction scoped Entity Manager der PersistenceContext an einen Service-Aufruf gebunden ist, erweitert der Extended Scope die Gültigkeit des PersistenceContext auf mehrere Aufrufe.
Solche EntityManager werden nicht vom Container (EJB/Spring) injected, sondern über die Klasse Persistence
und eine EntityManagerFactory
selbst erzeugt:
Hierfür wird allerdings eine Datei persistence.xml
benötigt.
https://vladmihalcea.com/2014/10/23/hibernate-application-level-repeatable-reads/
Generell kennt JPA vier Isolation Levels:
javax.sql.Connection.TRANSACTION_READ_COMMITTED
: Dirty reads are prevented; non-repeatable reads and phantom reads can occur.
javax.sql.Connection.TRANSACTION_READ_UNCOMMITTED
: Dirty reads, non-repeatable reads and phantom reads can occur.
javax.sql.Connection.TRANSACTION_REPEATABLE_READ
: Dirty reads and non-repeatable reads are prevented; phantom reads can occur.
javax.sql.Connection.TRANSACTION_SERIALIZABLE
: Dirty reads, non-repeatable reads, and phantom reads are prevented.
Isolation Levels sind IMMER auf der Datenbank und nicht im EntityManager implementiert, da Datenbanken verschiedene Clients bedienen (z. B. auch SQL-Navigatoren).
Der Grund besteht in einer besseren Performance oder der Vermeidung von Deadlock-Situationen bei weiterhin guter Datenkonsistenz.
https://dev.mysql.com/doc/refman/5.7/en/innodb-transaction-isolation-levels.html
https://dev.mysql.com/doc/refman/5.7/en/innodb-consistent-read.html
MySQL verwendet eine spezielle Implementierung basierend auf Snapshots, um Repeatable-Read umzusetzen. Auf diese Weise wird vermieden, daß lesende Zugriffe zu Locks führen und damit schreibende Zugriffe blockieren. Das erhöht den Durchsatz dramatisch und reduziert die Anfälligkeit für Deadlocks - zudem wird das Programmiermodell einfacher, weil Deadlock-Szenarien seletener auftreten können. Folgendes ist somit kein Problem:
TX 1 - a: lese Person P1
TX 2 - a: lese Person P1
TX 2 - b: ändere Person P1
Bei einer Standard-Repeatable-Read-Implementierung über READ-Locks müßte in "TX 2 - b" auf das Löschen des in "TX 1 - a" erzeugten READ-Locks gewartet werden. Bei der MySQL-Implementierung ist kein Warten notwendig.
Das Programmiermodell wird dadurch vereinfach:
wÜrden TX 1 und TX 2 innerhalb eines Threads abgearbeitet (z. B. mit einer REQUIRES_NEW Semantik), dann würde das in einer Standard-Reapeatable-Read-Implementierung zu einem Deadlock führen. Bei MySQL ist das problemlos möglich!!!
Bei der MySQL-Implementierung ist dieses Nutzungsszenario unkritisch.
... sollte man grundsätzlich versuchen zu vermeiden.
ABER: in manchen Fällen mag es nicht anders gehen, daß man transaktionales Verhalten über mehrere HTTP-Requests implementiert.
Extended PersistenceContext: https://vladmihalcea.com/2014/09/22/preventing-lost-updates-in-long-conversations/
Viele Datenbanken implementieren weitere Isolation Levels (z. B. ) bzw. spezielle Interpretationen/Implementierungen (z. B. ).