Útmutató Jakarta EE JTA-hoz

1. Áttekintés

Java Transaction API, közismertebb nevén JTA, egy API a Java tranzakciók kezelésére. Lehetővé teszi számunkra, hogy erőforrás-agnosztikus módon indítsunk, hajtsunk végre és visszavonjunk tranzakciókat.

A JTA valódi ereje abban rejlik, hogy több erőforrást (azaz adatbázisokat, üzenetküldő szolgáltatásokat) egyetlen tranzakcióban kezelhet.

Ebben az oktatóanyagban fogalmi szinten megismerjük a JTA-t, és meglátjuk, hogy az üzleti kód hogyan lép kölcsönhatásba a JTA-val.

2. Univerzális API és elosztott tranzakció

A JTA absztrakciót biztosít az üzleti kód tranzakcióvezérléséhez (kezdet, véglegesítés és visszagörgetés).

Ennek az absztrakciónak a hiányában az egyes erőforrástípusok egyedi API -ival kell foglalkoznunk.

Például az ilyen JDBC erőforrásokkal kell foglalkoznunk. Hasonlóképpen, egy JMS erőforrásnak is lehet hasonló, de nem kompatibilis modellje.

A JTA-val megtehetjük több, különböző típusú erőforrás kezelése következetes és összehangolt módon.

API-ként a JTA meghatározza az általuk megvalósítandó interfészeket és szemantikákat tranzakciókezelők. A megvalósításokat olyan könyvtárak biztosítják, mint a Narayana és a Bitronix.

3. Minta projektbeállítás

A mintaalkalmazás egy banki alkalmazás nagyon egyszerű háttérszolgáltatása. Két szolgáltatásunk van, a BankAccountService és AuditService két különböző adatbázis felhasználásával. Ezeket a független adatbázisokat össze kell hangolni a tranzakció megkezdésekor, végrehajtásakor vagy visszagörgetésekor.

Először is, mintaprojektünk a Spring Boot programot használja a konfiguráció egyszerűsítésére:

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

Végül az egyes vizsgálati módszerek előtt inicializáljuk AUDIT_LOG üres adatokkal és adatbázissal SZÁMLA 2 sorral:

+ ----------- + ---------------- + | ID | MÉRLEG | + ----------- + ---------------- + | a0000001 | 1000 | | a0000002 | 2000 | + ----------- + ---------------- +

4. Nyilatkozati ügylethatárolás

A JTA-ban végzett tranzakciók kezelésének első módja a @ Tranzakció annotáció. Részletesebb magyarázat és konfiguráció a cikkben található.

Jegyezzük fel a homlokzati szolgáltatási módszert executeTranser () val vel @ Tranzakció. Ez utasítja a tranzakciókezelő hogy tranzakcióba kezdjen:

@Transactional public void executeTransfer (String fromAccontId, String toAccountId, BigDecimal summa) {bankAccountService.transfer (fromAccontId, toAccountId, összeg); auditService.log (fromAccontId, toAccountId, összeg); ...}

Itt a módszer executeTranser () 2 különböző szolgáltatást hív, AccountService és AuditService. Ezek a szolgáltatások 2 különböző adatbázist használnak.

Mikor executeTransfer () visszatér, a tranzakciókezelő elismeri, hogy a tranzakció vége, és elkötelezi magát mindkét adatbázis mellett:

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. Visszagörgetés a deklaratív elhatárolásban

A módszer végén executeTransfer () ellenőrzi a számlaegyenleget és dob RuntimeException ha a forrásalap nem elegendő:

@Transactional public void executeTransfer (String fromAccontId, String toAccountId, BigDecimal summa) {bankAccountService.transfer (fromAccontId, toAccountId, összeg); auditService.log (fromAccontId, toAccountId, összeg); BigDecimal egyenleg = bankAccountService.balanceOf (fromAccontId); if (balance.compareTo (BigDecimal.ZERO) <0) {dobjon új RuntimeException-t ("Elégtelen forrás"); }}

An kezeletlenül RuntimeException az elsőn túl @ Tranzakció visszavonja a tranzakciótmindkét adatbázisba. Valójában az egyenlegnél nagyobb összegű átutalás visszagörgetést okoz:

assertThatThrownBy (() -> {tellerService.executeTransfer ("a0000002", "a0000001", BigDecimal.valueOf (10000));}). hasMessage ("Elégtelen az alap."); assertThat (accountService.balanceOf ("a0000001")). isEqualByComparingTo (BigDecimal.valueOf (1000)); assertThat (accountService.balanceOf ("a0000002")). isEqualByComparingTo (BigDecimal.valueOf (2000)); assertThat (auditServie.lastTransferLog ()). isNull ();

5. Programozott tranzakciók elhatárolása

A JTA tranzakciók ellenőrzésének másik módja a programon keresztül UserTransaction.

Most módosítsunk executeTransfer () a tranzakció kézi kezeléséhez:

userTransaction.begin (); bankAccountService.transfer (fromAccontId, toAccountId, összeg); auditService.log (fromAccontId, toAccountId, összeg); BigDecimal egyenleg = bankAccountService.balanceOf (fromAccontId); if (balance.compareTo (BigDecimal.ZERO) <0) {userTransaction.rollback (); dobjon új RuntimeException-t ("Elégtelen az alap."); } else {userTransaction.commit (); }

Példánkban a kezdődik() módszer új tranzakciót indít. Ha az egyenleg érvényesítése nem sikerül, hívjuk visszagörgetés () amely mindkét adatbázison átgördül. Másképp, a hívás elkövetni() mindkét adatbázisban végrehajtja a változtatásokat.

Fontos megjegyezni, hogy mindkettő elkövetni() és visszagörgetés () az aktuális tranzakció befejezése.

Végül az automatizált elhatárolás használata rugalmasságot biztosít számunkra a finom tranzakciók ellenőrzésében.

6. Következtetés

Ebben a cikkben megvitattuk azt a problémát, amelyet a JTA megpróbál megoldani. A kód példák illusztrálja a tranzakció vezérlését kommentárokkal és programozottan, 2 tranzakciós erőforrást érintve, amelyeket egyetlen tranzakcióban kell koordinálni.

Szokás szerint a kódpélda megtalálható a GitHub oldalon.