Sprievodca po Jakarte EE JTA

1. Prehľad

Java Transaction API, všeobecnejšie známe ako JTA, je API na správu transakcií v Jave. Umožňuje nám to spúšťať, potvrdzovať a odvolávať transakcie spôsobom zameraným na zdroje.

Skutočná sila platformy JTA spočíva v jej schopnosti spravovať viac zdrojov (t. J. Databáz, služieb zasielania správ) v jednej transakcii.

V tomto tutoriáli sa oboznámime s JTA na koncepčnej úrovni a uvidíme, ako obchodný kód bežne interaguje s JTA.

2. Universal API a distribuovaná transakcia

JTA poskytuje abstrakciu nad riadením transakcií (začatie, potvrdenie a vrátenie) do obchodného zákonníka.

Ak by táto abstrakcia neexistovala, museli by sme sa zaoberať jednotlivými API každého typu zdroja.

Napríklad musíme narábať s takýmto prostriedkom JDBC. Rovnako môže mať prostriedok JMS podobný, ale nekompatibilný model.

S JTA môžeme spravujte viac zdrojov rôznych typov konzistentne a koordinovane.

Ako API JTA definuje rozhrania a sémantiku, ktoré má implementovať transakční manažéri. Implementácie poskytujú knižnice ako Narayana a Bitronix.

3. Ukážka nastavenia projektu

Vzorová aplikácia je veľmi jednoduchá služba typu back-end bankovej aplikácie. Máme dve služby, BankAccountService a AuditService pomocou dvoch rôznych databáz. Tieto nezávislé databázy musia byť koordinované po začiatku transakcie, potvrdení alebo vrátení transakcie.

Náš ukážkový projekt najskôr používa Spring Boot na zjednodušenie konfigurácie:

 org.springframework.boot spring-boot-starter-parent 2.2.2.RELEASE org.springframework.boot spring-boot-starter-jta-bitronix 

Nakoniec pred každou testovacou metódou inicializujeme AUDIT_LOG s prázdnymi údajmi a databázou ÚČET s 2 riadkami:

+ ----------- + ---------------- + | ID | Zostatok | + ----------- + ---------------- + | a0000001 | 1 000 | | a0000002 | 2000 | + ----------- + ---------------- +

4. Deklaratívne vymedzenie transakcie

Prvý spôsob práce s transakciami v JTA je použitie @ Transakčné anotácia. Podrobnejšie vysvetlenie a konfiguráciu nájdete v tomto článku.

Poďme anotovať spôsob obsluhy fasády executeTranser () s @ Transakčné. To dáva pokyn transakčný manažér začať transakciu:

@Transactional public void executeTransfer (reťazec odAccontId, reťazec toAccountId, veľkáDecimálna suma) {bankAccountService.transfer (odAccontId, toAccountId, suma); auditService.log (fromAccontId, toAccountId, suma); ...}

Tu metóda executeTranser () volá 2 rôzne služby, AccountService a AuditService. Tieto služby využívajú 2 rôzne databázy.

Kedy executeTransfer () vracia, the transakčný manažér uznáva, že je to koniec transakcie, a zaviaže sa k obom databázam:

tellerService.executeTransfer ("a0000001", "a0000002", BigDecimal.valueOf (500)); assertThat (accountService.balanceOf ("a0000001")) .isEqualByComparingTo (BigDecimal.valueOf (500)); assertThat (accountService.balanceOf ("a0000002")) .isEqualByComparingTo (BigDecimal.valueOf (2500)); TransferLog lastTransferLog = auditService .lastTransferLog (); assertThat (lastTransferLog) .isNotNull (); assertThat (lastTransferLog.getFromAccountId ()) .isEqualTo ("a0000001"); assertThat (lastTransferLog.getToAccountId ()) .isEqualTo ("a0000002"); assertThat (lastTransferLog.getAmount ()) .isEqualByComparingTo (BigDecimal.valueOf (500));

4.1. Vrátenie sa v deklaratívnom ohraničení

Na konci metódy executeTransfer () skontroluje stav účtu a hodí RuntimeException ak je zdrojový fond nedostatočný:

@Transactional public void executeTransfer (reťazec zAccontId, reťazec toAccountId, veľkáDecimálna suma) {bankAccountService.transfer (odAccontId, toAccountId, suma); auditService.log (fromAccontId, toAccountId, suma); BigDecimal balance = bankAccountService.balanceOf (fromAccontId); if (balance.compareTo (BigDecimal.ZERO) <0) {hodiť novú RuntimeException („Nedostatočný fond.“); }}

An neošetrený RuntimeException za prvou @ Transakčné vráti transakciudo oboch databáz. Vykonanie prevodu s sumou väčšou ako je zostatok v skutočnosti spôsobí vrátenie platby:

assertThatThrownBy (() -> {tellerService.executeTransfer ("a0000002", "a0000001", BigDecimal.valueOf (10 000));}). hasMessage ("Nedostatočný fond."); assertThat (accountService.balanceOf ("a0000001")). isEqualByComparingTo (BigDecimal.valueOf (1000)); assertThat (accountService.balanceOf ("a0000002")). isEqualByComparingTo (BigDecimal.valueOf (2000)); assertThat (auditServie.lastTransferLog ()). isNull ();

5. Programové vymedzenie transakcie

Ďalším spôsobom, ako riadiť transakciu JTA, je programovo prostredníctvom UserTransaction.

Teraz poďme upraviť executeTransfer () na ručné spracovanie transakcie:

userTransaction.begin (); bankAccountService.transfer (fromAccontId, toAccountId, suma); auditService.log (fromAccontId, toAccountId, suma); BigDecimal balance = bankAccountService.balanceOf (fromAccontId); if (balance.compareTo (BigDecimal.ZERO) <0) {userTransaction.rollback (); hodiť nový RuntimeException ("Nedostatočný fond."); } else {userTransaction.commit (); }

V našom príklade začať() metóda spustí novú transakciu. Ak overenie zostatku zlyhá, zavoláme rollback () ktorý sa vráti späť cez obe databázy. Inak, hovor na spáchať () zaviaže zmeny do oboch databáz.

Je dôležité si uvedomiť, že oboje spáchať () a rollback () ukončiť aktuálnu transakciu.

V konečnom dôsledku nám programové vymedzenie umožňuje flexibilitu podrobnej kontroly transakcií.

6. Záver

V tomto článku sme diskutovali o probléme, ktorý sa snaží vyriešiť JTA. Príklady kódu ilustrujú kontrolnú transakciu s anotáciami a programovo, zahŕňajúci 2 transakčné zdroje, ktoré je potrebné koordinovať v jednej transakcii.

Ako obvykle, príklad kódu nájdete na GitHub.


$config[zx-auto] not found$config[zx-overlay] not found