Elosztott tranzakciókezelés Spring Boottal

A tranzakciókezelésről már többször írtam. Egy bevezető elérhető a Tranzakciókezelés EJB 3 és Spring környezetben címen is, melyet most frissítettem.

A jelenlegi posztban viszont azt írom le, hogyan lehet Spring Boottal elosztott tranzakciókezelést végezni.

Elosztott tranzakciókezelést akkor használunk, ha egy tranzakcióba szeretnénk foglalni két külön adatbázisban történő műveletet, vagy még gyakoribb példa, ha egy tranzakcióba szeretnénk foglalni egy adatbázis beszúrást és egy JMS üzenet elküldését. Látható, hogy nem csak adatbázisok képesek tranzakcióban részt venni, hanem pl. JMS-en elérhető üzenetkezelő middleware-ek (Message Oriented Middleware - MOM) is. Összefoglaló nevén ezek un. erőforráskezelők.

Az elosztott tranzakciókezeléshez egy tranzakció koordinátort kell kinevezni, aki irányítja a tranzakciót. Itt jön képbe a two-phase commit protocol (2PC), ahol első körben az erőforráskezelők felkészülnek a tranzakcióra, és második körben hagyják jóvá azt. Minden erőforráskezelőnek vétójoga van. Az erőforráskezelők a tranzakció koordinátorral az X/Open XA protokollon keresztül kommunikálnak.

Java környezetben elosztott tranzakciók kezelésére a JTA szabványt használjuk. Ez két részből áll. A javax.transaction csomagban lévő interfészek és annotációk lehetővé teszik, hogy az alkalmazás a tranzakciókra vonatkozó szabályokat adjon meg. Itt van pl. a @javax.transaction.Transactional annotáció. Spring esetén nem ezt, hanem a saját @org.springframework.transaction.annotation.Transactional annotációját használjuk. A javax.transaction.xa csomagban lévő interfészek pedig API-t biztosítanak a tranzakció koordinátor (, melyet a JTA Transaction Managernek hív) és az erőforráskezelők (Resource Manager) közötti kommunikációra. Így tudnak egymáshoz lazán kapcsolódva együttműködni.

JTA

Több JTA implementáció is van, mint pl. az Atomicos vagy Narayana. A Spring jelenleg az Atomicost támogatja. Ehhez használatához csak annyit kell tenni, hogy a hozzá tartozó starter projektet fel kell venni függőségként a pom.xml állományba.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>

A https://github.com/vicziani/jtechlog-jms-transaction címen található egy példa projekt. Ez elindít egy beágyazott H2 adatbázist, melyhez Spring Data JPA-val fér hozzá. Valamint elindít egy beágyazott Apache Artemis JMS providert.

Alkalmazás

Ha beküldünk egy kérést, akkor az EmployeesService indít egy tranzakciót, és beszúr egy rekordot az employees táblába az EmployeeRepository használatával, valamint elküld egy üzenetet a employees.queue sorba a JmsTemplate használatával. A sort egy EmployeesQueueListener figyeli, mely ha üzenetet kap, továbbhív az EventsService-be. Ha egy kivételt dobunk, akkor sem az adatbázis beszúrás, sem a JMS üzenetküldés nem kerül végrehajtásra, hiszen mindkettő rollbackel.

A projekthez egy EmployeesIT integrációs teszt is tartozik, mely teszteli a helyes értékkel a commitot és helytelen értékkel a rollbacket. Egyrészt adatbázisból lekérdezi a rekordokat. Másrészt mockolja az EventsService-t, és azt figyeli, hogy annak metódusa meghívásra került-e, ezzel vizsgálva, hogy érkezett-e üzenet a sorba.