Antworten:
Gute Frage, wenn auch nicht trivial zu beantworten.
Definiert, wie Transaktionen zueinander in Beziehung stehen. Allgemeine Optionen:
Required
: Code wird immer in einer Transaktion ausgeführt. Erstellt eine neue Transaktion oder verwendet eine, falls verfügbar.Requires_new
: Code wird immer in einer neuen Transaktion ausgeführt. Hält die aktuelle Transaktion an, falls vorhanden.Definiert den Datenvertrag zwischen Transaktionen.
Read Uncommitted
: Ermöglicht Dirty Reads.Read Committed
: Ermöglicht keine schmutzigen Lesevorgänge.Repeatable Read
: Wenn eine Zeile in derselben Transaktion zweimal gelesen wird, ist das Ergebnis immer dasselbe.Serializable
: Führt alle Transaktionen in einer Sequenz aus.Die verschiedenen Ebenen weisen in einer Multithread-Anwendung unterschiedliche Leistungsmerkmale auf. Ich denke, wenn Sie das dirty reads
Konzept verstehen , können Sie eine gute Option auswählen.
Beispiel dafür, wann ein Dirty Read auftreten kann:
thread 1 thread 2
| |
write(x) |
| |
| read(x)
| |
rollback |
v v
value (x) is now dirty (incorrect)
Ein vernünftiger Standardwert (falls dies behauptet werden kann) könnte also sein Read Committed
, mit dem Sie nur Werte lesen können, die bereits von anderen laufenden Transaktionen festgeschrieben wurden, in Kombination mit einer Ausbreitungsstufe von Required
. Dann können Sie von dort aus arbeiten, wenn Ihre Anwendung andere Anforderungen hat.
Ein praktisches Beispiel dafür, wo beim Eingeben der provideService
Routine immer eine neue Transaktion erstellt und beim Verlassen abgeschlossen wird:
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 verwendet Required
, würde die Transaktion offen bleiben, wenn die Transaktion bereits beim Aufrufen der Routine geöffnet wäre. Beachten Sie auch, dass das Ergebnis von a rollback
unterschiedlich sein kann, da mehrere Ausführungen an derselben Transaktion teilnehmen können.
Wir können das Verhalten leicht mit einem Test überprüfen und feststellen, wie sich die Ergebnisse mit den Ausbreitungsniveaus 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
: Würden wir erwarten , fooService.provideService()
war nicht seine eigene Unter Transaktion , da sie erstellt zurückgerollt.
Required
: Wir würden erwarten, dass alles zurückgesetzt wurde und der Backing Store unverändert blieb.
sessionFactory.getCurrentTransaction()
hinzugefügt wurde, besteht keine Notwendigkeit HibernateTemplate
mehr, um Transaktionen zu verwalten. Ich habe es entfernt :)
PROPAGATION_REQUIRED = 0 ; Wenn DataSourceTransactionObject T1 bereits für Methode M1 gestartet wurde. Wenn für eine andere Methode M2 ein Transaktionsobjekt erforderlich ist, wird kein neues Transaktionsobjekt erstellt. Das gleiche Objekt T1 wird für M2 verwendet
PROPAGATION_MANDATORY = 2 ; Methode muss innerhalb einer Transaktion ausgeführt werden. Wenn keine vorhandene Transaktion ausgeführt wird, wird eine Ausnahme ausgelöst
PROPAGATION_REQUIRES_NEW = 3 ; Wenn DataSourceTransactionObject T1 bereits für Methode M1 gestartet wurde und ausgeführt wird (Ausführung von Methode M1). Wenn eine andere Methode M2 ausgeführt wird, wird T1 für die Dauer der Methode M2 angehalten, wobei das neue DataSourceTransactionObject T2 für M2.M2 in seinem eigenen Transaktionskontext ausgeführt wird
PROPAGATION_NOT_SUPPORTED = 4 ; Wenn DataSourceTransactionObject T1 bereits für Methode M1 gestartet wurde. Wenn eine andere Methode M2 gleichzeitig ausgeführt wird. Dann sollte M2 nicht im Transaktionskontext ausgeführt werden. T1 wird ausgesetzt, bis M2 fertig ist.
PROPAGATION_NEVER = 5 ; Keine der Methoden wird im Transaktionskontext ausgeführt.
Isolationsstufe: Es geht darum, wie stark eine Transaktion von den Aktivitäten anderer gleichzeitiger Transaktionen beeinflusst werden kann. Sie unterstützt die Konsistenz und lässt die Daten über viele Tabellen hinweg in einem konsistenten Zustand. Dabei werden Zeilen und / oder Tabellen in einer Datenbank gesperrt.
Das Problem mit mehreren Transaktionen
Szenario 1. Wenn die T1-Transaktion Daten aus Tabelle A1 liest, die von einer anderen gleichzeitigen Transaktion T2 geschrieben wurden. Wenn auf dem Weg T2 ein Rollback durchgeführt wird, sind die von T1 erhaltenen Daten ungültig. Beispiel a = 2 sind Originaldaten. Wenn T1 a = liest 1, die von T2 geschrieben wurde. Wenn T2-Rollback ausgeführt wird, wird a = 1 in DB auf a = 2 zurückgesetzt. Jetzt hat T1 a = 1, aber in der DB-Tabelle wird es in a = 2 geändert.
Szenario2 2. Wenn die T1-Transaktion Daten aus Tabelle A1 liest. Wenn eine andere gleichzeitige Transaktion (T2) Daten in Tabelle A1 aktualisiert. Die Daten, die T1 gelesen hat, unterscheiden sich von Tabelle A1. Weil T2 die Daten in Tabelle A1 aktualisiert hat Lesen Sie a = 1 und T2 aktualisiert a = 2. Dann a! = b.
Szenario 3 Wenn die T1-Transaktion Daten aus Tabelle A1 mit einer bestimmten Anzahl von Zeilen liest. Wenn eine andere gleichzeitige Transaktion (T2) mehr Zeilen in Tabelle A1 einfügt. Die Anzahl der von T1 gelesenen Zeilen unterscheidet sich von den Zeilen in Tabelle A1
Szenario 1 wird aufgerufen Dirty Reads.
Szenario 2 heißt Nicht wiederholbare Lesevorgänge.
Szenario 3 wird aufgerufen Phantom Reads.
Die Isolationsstufe ist also die Ausdehnung, bis zu der Szenario 1, Szenario 2, Szenario 3 verhindert werden kann. Sie können eine vollständige Isolationsstufe erhalten, indem Sie die Sperrung implementieren. Dadurch wird verhindert, dass gleichzeitig dieselben Daten gelesen und geschrieben werden. Dies wirkt sich jedoch auf die Leistung aus. Die Isolationsstufe hängt von Anwendung zu Anwendung ab, wie viel Isolation erforderlich ist.
ISOLATION_READ_UNCOMMITTED : Ermöglicht das Lesen von Änderungen, die noch nicht festgeschrieben wurden. Es leidet unter Szenario 1, Szenario 2, Szenario 3
ISOLATION_READ_COMMITTED : Ermöglicht das Lesen von gleichzeitig festgeschriebenen Transaktionen. Es kann unter Szenario 2 und Szenario 3 leiden, da andere Transaktionen möglicherweise die Daten aktualisieren.
ISOLATION_REPEATABLE_READ : Mehrere Lesevorgänge desselben Feldes führen zu denselben Ergebnissen, bis es von selbst geändert wird. Es kann unter Szenario 3 leiden. Andere Transaktionen fügen möglicherweise die Daten ein
ISOLATION_SERIALIZABLE : Szenario 1, Szenario 2, Szenario 3 tritt nie auf. Es handelt sich um eine vollständige Isolierung. Es handelt sich um eine vollständige Sperrung. Die Leistung wird aufgrund der Sperrung beeinträchtigt.
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 die Isolierung und Weitergabe debuggen und anzeigen.
Genügend Erklärungen zu jedem Parameter werden durch andere Antworten gegeben; Wie auch immer Sie nach einem Beispiel aus der realen Welt gefragt haben, hier ist das, das den Zweck der unterschiedlichen Verbreitung verdeutlicht :
Angenommen, Sie sind für die Implementierung eines Anmeldedienstes verantwortlich, bei dem eine Bestätigungs-E-Mail an den Benutzer gesendet wird. Sie haben zwei Serviceobjekte, eines zum Registrieren des Benutzers und eines zum Senden von E-Mails, das im ersten aufgerufen wird. Zum Beispiel so etwas:/* 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)
}
}
Möglicherweise haben Sie bemerkt, dass der zweite Dienst vom Weitergabe-Typ REQUIRES_NEW ist und es besteht außerdem die Möglichkeit, dass er eine Ausnahme (SMTP-Server heruntergefahren, ungültige E-Mail oder aus anderen Gründen). Sie möchten wahrscheinlich nicht, dass der gesamte Prozess zurückgesetzt wird Entfernen der Benutzerinformationen aus der Datenbank oder anderen Dingen; Daher rufen Sie den zweiten Dienst in einer separaten Transaktion auf.
Zurück zu unserem Beispiel: Dieses Mal sind Sie besorgt über die Datenbanksicherheit. Definieren Sie Ihre DAO-Klassen folgendermaßen:/* User DAO */
@Transactional(Propagation=MANDATORY)
class UserDAO{
// some CRUD methods
}
Das heißt, wenn ein DAO-Objekt und damit ein potenzieller Zugriff auf db erstellt wird, müssen wir sicherstellen, dass der Anruf von einem unserer Dienste aus getätigt wurde, was bedeutet, dass eine Live-Transaktion vorhanden sein sollte. Andernfalls tritt eine Ausnahme auf. Daher ist die Weitergabe vom Typ OBLIGATORISCH .
Die Isolationsstufe definiert, wie sich die von einer Transaktion an einem Datenrepository vorgenommenen Änderungen auf andere gleichzeitige Transaktionen auswirken und wie und wann diese geänderten Daten für andere Transaktionen verfügbar werden. Wenn wir eine Transaktion mithilfe des Spring-Frameworks definieren, können wir auch konfigurieren, in welcher Isolationsstufe dieselbe Transaktion ausgeführt wird.
@Transactional(isolation=Isolation.READ_COMMITTED)
public void someTransactionalMethod(Object obj) {
}
Die Isolationsstufe READ_UNCOMMITTED gibt an, dass eine Transaktion Daten lesen kann, die von anderen Transaktionen noch nicht festgeschrieben wurden.
Die Isolationsstufe READ_COMMITTED gibt an, dass eine Transaktion keine Daten lesen kann, die noch nicht von anderen Transaktionen festgeschrieben wurden.
Die Isolationsstufe REPEATABLE_READ gibt an, dass das Ergebnis all dieser Lesevorgänge immer dasselbe sein muss, wenn eine Transaktion einen Datensatz mehrmals aus der Datenbank liest.
Die SERIALIZABLE-Isolationsstufe ist die restriktivste aller Isolationsstufen. Transaktionen werden mit Sperren auf allen Ebenen (Lese-, Bereichs- und Schreibsperren) ausgeführt, sodass sie so aussehen, als ob sie serialisiert ausgeführt wurden.
Die Weitergabe ist die Fähigkeit zu entscheiden, wie die Geschäftsmethoden sowohl in logischen als auch in physischen Transaktionen gekapselt werden sollen.
Spring REQUIRED-Verhalten bedeutet, dass dieselbe Transaktion verwendet wird, wenn im aktuellen Ausführungskontext der Bean-Methode bereits eine Transaktion geöffnet ist.
REQUIRES_NEW-Verhalten bedeutet, dass der Container immer eine neue physische Transaktion erstellt.
Das NESTED-Verhalten bewirkt, dass verschachtelte Spring-Transaktionen dieselbe physische Transaktion verwenden, jedoch Sicherungspunkte zwischen verschachtelten Aufrufen festlegen, sodass innere Transaktionen auch unabhängig von äußeren Transaktionen zurückgesetzt werden können.
Das OBLIGATORY-Verhalten besagt, dass eine vorhandene geöffnete Transaktion bereits vorhanden sein muss. Wenn nicht, wird vom Container eine Ausnahme ausgelöst.
Das Verhalten NIE besagt, dass eine vorhandene geöffnete Transaktion noch nicht vorhanden sein darf. Wenn eine Transaktion vorhanden ist, wird vom Container eine Ausnahme ausgelöst.
Das NOT_SUPPORTED-Verhalten wird außerhalb des Bereichs einer Transaktion ausgeführt. Wenn bereits eine geöffnete Transaktion vorhanden ist, wird diese angehalten.
Das SUPPORTS-Verhalten wird im Rahmen einer Transaktion ausgeführt, wenn bereits eine geöffnete Transaktion vorhanden ist. Wenn noch keine Transaktion geöffnet ist, wird die Methode trotzdem ausgeführt, jedoch nicht transaktionsbezogen.
Eine Transaktion repräsentiert eine Arbeitseinheit mit einer Datenbank.
In-Spring- TransactionDefinition
Schnittstelle, die Spring-konforme Transaktionseigenschaften definiert. @Transactional
Annotation beschreibt Transaktionsattribute für eine 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 (Reproduktion): Wird für die Intertransaktionsbeziehung verwendet. (analog zur Java Inter Thread Kommunikation)
+-------+---------------------------+------------------------------------------------------------------------------------------------------+
| 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. |
+-------+---------------------------+------------------------------------------------------------------------------------------------------+
Isolation: Die Isolation ist eine der ACID-Eigenschaften (Atomicity, Consistency, Isolation, Durability) von Datenbanktransaktionen. Die Isolation bestimmt, wie die Transaktionsintegrität für andere Benutzer und Systeme sichtbar ist. Es wird zum Sperren von Ressourcen verwendet, dh zum Steuern der Parallelität. Stellen Sie sicher, dass zu einem bestimmten Zeitpunkt nur eine Transaktion auf die Ressource zugreifen kann.
Sperrwahrnehmung: Die Isolationsstufe bestimmt die Dauer, in der 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 |
+---------------------------+-------------------+-------------+-------------+------------------------+
Lesewahrnehmung: Die folgenden 3 Arten von Hauptproblemen treten auf:
UPDATES
von einem anderen Sender festgeschrieben wurden .INSERTS
und / oder DELETES
von einem anderen txIsolationsstufen mit verschiedenen Arten von Lesevorgängen:
+---------------------------+----------------+----------------------+----------------+
| Isolation Level Mode | Dirty reads | Non-repeatable reads | Phantoms reads |
+---------------------------+----------------+----------------------+----------------+
| READ_UNCOMMITTED | allows | allows | allows |
| READ_COMMITTED (Default) | prevents | allows | allows |
| REPEATABLE_READ | prevents | prevents | allows |
| SERIALIZABLE | prevents | prevents | prevents |
+---------------------------+----------------+----------------------+----------------+
Sie möchten fast nie verwenden, Read Uncommited
da es nicht wirklich ACID
konform ist. Read Commmited
ist ein guter Standardstartplatz. Repeatable Read
wird wahrscheinlich nur in Berichts-, Rollup- oder Aggregationsszenarien benötigt. Beachten Sie, dass viele DBs, einschließlich Postgres, Repeatable Read nicht unterstützen. Sie müssen Serializable
stattdessen verwenden. Serializable
ist nützlich für Dinge, von denen Sie wissen, dass sie völlig unabhängig von irgendetwas anderem geschehen müssen; Denken Sie daran wie synchronized
in Java. Serialisierbar geht Hand in Hand mit REQUIRES_NEW
Propagation.
Ich verwende REQUIRES
für alle Funktionen, die UPDATE- oder DELETE-Abfragen ausführen, sowie Funktionen auf "Service" -Ebene. Für DAO-Level-Funktionen, auf denen nur SELECTs ausgeführt werden, verwende ich, SUPPORTS
die an einem TX teilnehmen, wenn eines bereits gestartet wurde (dh von einer Servicefunktion aufgerufen wird).
Transaktionsisolation und Transaktionsausbreitung sind zwar verwandt, aber eindeutig zwei sehr unterschiedliche Konzepte. In beiden Fällen werden die Standardeinstellungen an der Client-Grenzkomponente entweder mithilfe der deklarativen Transaktionsverwaltung oder der programmatischen Transaktionsverwaltung angepasst . Details zu den einzelnen Isolationsstufen und Ausbreitungsattributen finden Sie unter den folgenden Referenzlinks.
Wie und wann wirken sich Änderungen, die von Abfragen in einer Transaktion vorgenommen werden, auf zwei oder mehr laufende Transaktionen / Verbindungen zu einer Datenbank aus, die für die Abfragen in einer anderen Transaktion sichtbar sind? Es bezog sich auch darauf, welche Art der Sperre von Datenbankdatensätzen verwendet wird, um Änderungen in dieser Transaktion von anderen Transaktionen zu isolieren und umgekehrt. Dies wird normalerweise von der Datenbank / Ressource implementiert, die an der Transaktion teilnimmt.
.
In einer Unternehmensanwendung für eine bestimmte Anforderung / Verarbeitung sind viele Komponenten beteiligt, um die Aufgabe zu erledigen. Einige dieser Komponenten markieren die Grenzen (Start / Ende) einer Transaktion, die in der jeweiligen Komponente und ihren Unterkomponenten verwendet wird. Für diese Transaktionsgrenze von Komponenten gibt Transaction Propogation an, ob die jeweilige Komponente an der Transaktion teilnehmen wird oder nicht und was passiert, wenn für die aufrufende Komponente bereits eine Transaktion erstellt / gestartet wurde oder nicht. Dies entspricht den Java EE-Transaktionsattributen. Dies wird normalerweise vom Client-Transaktions- / Verbindungsmanager implementiert.
Referenz:
Ich habe laufen outerMethod
, method_1
undmethod_2
mit unterschiedlichem Ausbreitungsmodus.
Unten ist die Ausgabe für verschiedene Ausbreitungsmodi.
Äußere Methode
@Transactional
@Override
public void outerMethod() {
customerProfileDAO.method_1();
iWorkflowDetailDao.method_2();
}
Methode 1
@Transactional(propagation=Propagation.MANDATORY)
public void method_1() {
Session session = null;
try {
session = getSession();
Temp entity = new Temp(0l, "XXX");
session.save(entity);
System.out.println("Method - 1 Id "+entity.getId());
} finally {
if (session != null && session.isOpen()) {
}
}
}
Methode_2
@Transactional()
@Override
public void method_2() {
Session session = null;
try {
session = getSession();
Temp entity = new Temp(0l, "CCC");
session.save(entity);
int i = 1/0;
System.out.println("Method - 2 Id "+entity.getId());
} finally {
if (session != null && session.isOpen()) {
}
}
}
Wir können dazu hinzufügen:
@Transactional(readOnly = true)
public class Banking_CustomerService implements CustomerService {
public Customer getDetail(String customername) {
// do something
}
// these settings have precedence for this method
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public void updateCustomer(Customer customer) {
// do something
}
}
Sie können wie folgt verwenden:
@Transactional(propagation = Propagation.REQUIRES_NEW)
public EventMessage<ModificaOperativitaRapporto> activate(EventMessage<ModificaOperativitaRapporto> eventMessage) {
//here some transaction related code
}
Sie können dieses Ding auch verwenden:
public interface TransactionStatus extends SavepointManager {
boolean isNewTransaction();
boolean hasSavepoint();
void setRollbackOnly();
boolean isRollbackOnly();
void flush();
boolean isCompleted();
}