Een gids voor Atomikos

1. Inleiding

Atomikos is een transactiebibliotheek voor Java-toepassingen. In deze tutorial zullen we begrijpen waarom en hoe Atomikos te gebruiken.

Tijdens het proces zullen we ook de basisprincipes van transacties doornemen en waarom we ze nodig hebben.

Vervolgens maken we een eenvoudige applicatie met transacties die gebruikmaken van verschillende API's van Atomikos.

2. Inzicht in de basisprincipes

Voordat we Atomikos bespreken, moeten we eerst begrijpen wat transacties precies zijn en enkele concepten die daarmee verband houden. Simpel gezegd, een transactie is een logische werkeenheid waarvan het effect buiten de transactie geheel of niet zichtbaar is.

Laten we een voorbeeld nemen om dit beter te begrijpen. Een typische retailtoepassing reserveert de inventaris en plaatst vervolgens een bestelling:

Hier willen we dat deze twee operaties samen gebeuren of helemaal niet. Dit kunnen we bereiken door deze operaties in één transactie te verpakken.

2.1. Lokale versus gedistribueerde transactie

Een transactie kan meerdere onafhankelijke operaties omvatten. Deze operaties kan worden uitgevoerd op dezelfde bron of verschillende bronnen. We verwijzen hier naar de deelnemende componenten in een transactie zoals een database als een bron.

Transacties binnen een enkele bron zijn bekende lokale transacties, terwijl transacties die over meerdere bronnen voortkomen, bekend staan ​​als de gedistribueerde transactie:

Hier kunnen voorraad en bestellingen twee tabellen in dezelfde database zijn, of het kunnen twee verschillende databases zijn - mogelijk in totaal op verschillende machines.

2.2. XA-specificatie en Java-transactie-API

XA verwijst naar eXtended Architecture, een specificatie voor gedistribueerde transactieverwerking. De doel van XA is om atomiciteit te verschaffen in wereldwijde transacties met heterogene componenten.

XA-specificatie biedt integriteit via een protocol dat bekend staat als een tweefasige commit. Commitment in twee fasen is een veelgebruikt gedistribueerd algoritme om de beslissing om een ​​gedistribueerde transactie vast te leggen of terug te draaien te vergemakkelijken.

Java Transaction API (JTA) is een Java Enterprise Edition API die is ontwikkeld onder het Java Community Process. Het stelt Java-applicaties en applicatieservers in staat om gedistribueerde transacties over XA-bronnen uit te voeren.

JTA is gemodelleerd rond de XA-architectuur, waarbij gebruik wordt gemaakt van committering in twee fasen. JTA specificeert standaard Java-interfaces tussen een transactiebeheerder en de andere partijen in een gedistribueerde transactie.

3. Inleiding tot Atomikos

Nu we de basisprincipes van transacties hebben doorgenomen, zijn we klaar om Atomikos te leren kennen. In deze sectie zullen we begrijpen wat Atomikos precies is en hoe het zich verhoudt tot concepten als XA en JTA. We zullen ook de architectuur van Atomikos begrijpen en het productaanbod doornemen.

3.1. Wat is Atomikos

Zoals we hebben gezien, biedt JTA interfaces in Java voor het bouwen van applicaties met gedistribueerde transacties. Nu is JTA slechts een specificatie en biedt geen enkele implementatie. Voor ons om een ​​applicatie uit te voeren waarin we gebruikmaken van JTA, hebben we een implementatie van JTA nodig. Een dergelijke implementatie wordt een transactiebeheerder genoemd.

Typisch biedt de applicatieserver een standaardimplementatie van de transactiebeheerder. In het geval van Enterprise Java Beans (EJB) bijvoorbeeld, beheren EJB-containers transactiegedrag zonder expliciete tussenkomst van applicatieontwikkelaars. In veel gevallen is dit echter niet ideaal en hebben we mogelijk directe controle over de transactie nodig, onafhankelijk van de applicatieserver.

Atomikos is een lichtgewicht transactiebeheerder voor Java waarmee applicaties die gedistribueerde transacties gebruiken, op zichzelf staan. In wezen hoeft onze applicatie voor transacties niet te vertrouwen op een zwaargewicht component zoals een applicatieserver. Dit brengt het concept van gedistribueerde transacties dichter bij een cloud-native architectuur.

3.2. Atomikos-architectuur

Atomikos is voornamelijk gebouwd als JTA-transactiemanager en daarom implementeert XA-architectuur met een tweefasig commit-protocol. Laten we eens kijken naar een architectuur op hoog niveau met Atomikos:

Hier faciliteert Atomikos een transactie op basis van vastlegging in twee fasen die zich uitstrekt over een database en een berichtenwachtrij.

3.3. Atomikos-productaanbiedingen

Atomikos is een gedistribueerde transactiebeheerder die meer functies biedt dan wat JTA / XA voorschrijft. Het heeft een open-sourceproduct en een veel uitgebreider commercieel aanbod:

  • TransactionsEssentials: Atomikos ' open-sourceproduct dat JTA / XA-transactiebeheer voor Java-toepassingen biedt werken met databases en berichtenwachtrijen. Dit is vooral handig voor test- en evaluatiedoeleinden.
  • ExtremeTransactions: het commercieel aanbod van Atomikos, dat gedistribueerde transacties biedt over samengestelde applicaties, inclusief REST-services, afgezien van databases en berichtenwachtrijen. Dit is handig om applicaties te bouwen die Extreme Transaction Processing (XTP) uitvoeren.

In deze tutorial gebruiken we de TransactionsEssentials-bibliotheek om de mogelijkheden van Atomikos te bouwen en te demonstreren.

4. Atomikos opzetten

Zoals we eerder hebben gezien, is dat een van de hoogtepunten van Atomikos het is een ingebedde transactieservice. Dit betekent dat we het in dezelfde JVM kunnen uitvoeren als onze applicatie. Het opzetten van Atomikos is dus vrij eenvoudig.

4.1. Afhankelijkheden

Eerst moeten we de afhankelijkheden instellen. Hier hoeven we alleen maar de afhankelijkheden in onze Maven te declareren pom.xml het dossier:

 com.atomikos transacties-jdbc 5.0.6 com.atomikos transacties-jms 5.0.6 

We gebruiken in dit geval Atomikos-afhankelijkheden voor JDBC en JMS, maar vergelijkbare afhankelijkheden zijn beschikbaar op Maven Central voor andere XA-klachtenbronnen.

4.2. Configuraties

Atomikos biedt verschillende configuratieparameters, met verstandige standaardinstellingen voor elk ervan. De eenvoudigste manier om deze parameters te negeren, is door verschaffen transacties.properties bestand in het klassenpad. We kunnen verschillende parameters toevoegen voor de initialisatie en werking van de transactieservice. Laten we eens kijken naar een eenvoudige configuratie om de map waarin logbestanden worden gemaakt te overschrijven:

com.atomikos.icatch.file = pad_naar_uw_bestand

Evenzo zijn er andere parameters die we kunnen gebruiken om de time-out voor transacties te regelen, unieke namen voor onze applicatie in te stellen of het afsluitgedrag te definiëren.

4.3. Databases

In onze tutorial bouwen we een eenvoudige retailtoepassing, zoals degene die we eerder hebben beschreven, die voorraad reserveert en vervolgens een bestelling plaatst. Voor de eenvoud zullen we een relationele database gebruiken. Bovendien gebruiken we meerdere databases om gedistribueerde transacties te demonstreren. Echter, dit kan heel goed worden uitgebreid tot andere XA-klachtenbronnen zoals berichtenwachtrijen en onderwerpen.

Onze inventarisdatabase heeft een eenvoudige tabel om productinventarissen te hosten:

TABELINVENTARIS MAKEN (productId VARCHAR PRIMAIRE SLEUTEL, balans INT);

En onze orderdatabase heeft een eenvoudige tafel om geplaatste bestellingen te hosten:

CREËER TABEL ORDERS (orderId VARCHAR PRIMARY KEY, productId VARCHAR, amount INT NOT NULL CHECK (amount <= 5));

Dit is een heel eenvoudig databaseschema en alleen nuttig voor de demonstratie. Het is echter belangrijk op te merken dat onze schemabeperking geen bestellingen toestaat met een producthoeveelheid van meer dan vijf.

5. Werken met Atomikos

Nu zijn we klaar om een ​​van de Atomikos-bibliotheken te gebruiken om onze applicatie met gedistribueerde transacties te bouwen. In de volgende paragrafen gebruiken we de ingebouwde Atomikos-bronadapters om verbinding te maken met onze back-end databasesystemen. Dit is de snelste en gemakkelijkste manier om aan de slag te gaan met Atomikos.

5.1. Instantiërend UserTransaction

We zullen JTA gebruiken UserTransaction om transactiegrenzen af ​​te bakenen. Alle andere stappen met betrekking tot transactieservice worden automatisch uitgevoerd. Dit omvat het in- en uitschrijven van bronnen bij de transactieservice.

Ten eerste moeten we een instantiëren UserTransaction van Atomikos:

UserTransactionImp utx = nieuwe UserTransactionImp ();

5.2. Instantiërend Databron

Vervolgens moeten we een instantiëren Databron van Atomikos. Er zijn twee versies van Databron die Atomikos beschikbaar stelt.

De eerste, AtomikosDataSourceBean, is zich bewust van een onderliggend XADataSource:

AtomikosDataSourceBean dataSource = nieuwe AtomikosDataSourceBean ();

Terwijl AtomikosNonXADataSourceBean gebruikt een gewone JDBC-stuurprogrammaklasse:

AtomikosNonXADataSourceBean dataSource = nieuwe AtomikosNonXADataSourceBean ();

Zoals de naam al doet vermoeden, AtomikosNonXADataSource is niet compatibel met XA. Daarom kan niet worden gegarandeerd dat transacties die met een dergelijke gegevensbron worden uitgevoerd, atomair zijn. Dus waarom zouden we dit ooit gebruiken? Mogelijk hebben we een database die de XA-specificatie niet ondersteunt. Atomikos verbiedt ons niet om een ​​dergelijke gegevensbron te gebruiken en probeert toch atomiciteit te bieden als er een enkele dergelijke gegevensbron in de transactie is. Deze techniek is vergelijkbaar met Last Resource Gambit, een variatie op het vastlegproces in twee fasen.

Verder moeten we het Databron afhankelijk van de database en het stuurprogramma.

5.3. Databasebewerkingen uitvoeren

Eenmaal geconfigureerd, is het vrij eenvoudig te gebruiken Databron in het kader van een transactie in onze applicatie:

public void placeOrder (String productId, int amount) gooit uitzondering {String orderId = UUID.randomUUID (). toString (); boolean rollback = false; probeer {utx.begin (); Verbinding inventoryConnection = inventoryDataSource.getConnection (); Verbinding orderConnection = orderDataSource.getConnection (); Verklaring s1 = inventoryConnection.createStatement (); String q1 = "update inventaris set balance = saldo -" + aantal + "waar productId = '" + productId + "'"; s1.executeUpdate (q1); s1.close (); Verklaring s2 = orderConnection.createStatement (); String q2 = "invoegen in Orders-waarden ('" + orderId + "', '" + productId + "'," + amount + ")"; s2.executeUpdate (q2); s2.close (); inventoryConnection.close (); orderConnection.close (); } catch (uitzondering e) {rollback = true; } eindelijk {if (! rollback) utx.commit (); anders utx.rollback (); }}

Hier werken we de databasetabellen bij voor voorraad en bestelling binnen de transactiegrens. Dit biedt automatisch het voordeel dat deze bewerkingen atomair plaatsvinden.

5.4. Transactiegedrag testen

Ten slotte moeten we onze applicatie kunnen testen met eenvoudige unit tests om te valideren dat het transactiegedrag is zoals verwacht:

@Test openbare ongeldige testPlaceOrderSuccess () gooit Uitzondering {int bedrag = 1; long initialBalance = getBalance (inventoryDataSource, productId); Applicatie applicatie = nieuwe applicatie (inventoryDataSource, orderDataSource); application.placeOrder (productId, bedrag); long finalBalance = getBalance (inventoryDataSource, productId); assertEquals (initialBalance - bedrag, finalBalance); } @Test openbare ongeldige testPlaceOrderFailure () gooit Uitzondering {int bedrag = 10; long initialBalance = getBalance (inventoryDataSource, productId); Applicatie applicatie = nieuwe applicatie (inventoryDataSource, orderDataSource); application.placeOrder (productId, bedrag); long finalBalance = getBalance (inventoryDataSource, productId); assertEquals (initialBalance, finalBalance); }

Hier, we verwachten dat een geldige order de voorraad verkleint, terwijl we verwachten dat een ongeldige order de voorraad ongewijzigd laat. Houd er rekening mee dat, volgens onze databasebeperking, elke bestelling met een hoeveelheid van meer dan vijf van een product als een ongeldige bestelling wordt beschouwd.

5.5. Geavanceerd Atomikos-gebruik

Het bovenstaande voorbeeld is de eenvoudigste manier om Atomikos te gebruiken en wellicht voldoende voor de meeste vereisten. Er zijn echter andere manieren waarop we Atomikos kunnen gebruiken om onze applicatie te bouwen. Hoewel sommige van deze opties Atomikos gebruiksvriendelijk maken, bieden andere meer flexibiliteit. De keuze hangt af van onze eisen.

Natuurlijk is het het is niet nodig om altijd Atomikos-adapters te gebruiken voor JDBC / JMS. We kunnen ervoor kiezen om de transactiebeheerder van Atomikos te gebruiken terwijl we rechtstreeks werken met XAResource. In dat geval moeten wij echter expliciet zorg dragen voor aan- en afschrijving XAResource instanties met de transactieservice.

Atomikos maakt het ook mogelijk om te gebruiken meer geavanceerde functies via een eigen interface, UserTransactionService. Met behulp van deze interface kunnen we expliciet bronnen registreren voor herstel. Dit geeft ons een fijnmazige controle over welke bronnen moeten worden hersteld, hoe ze moeten worden hersteld en wanneer herstel moet plaatsvinden.

6. Atomikos integreren

Hoewel Atomikos uitstekende ondersteuning biedt voor gedistribueerde transacties, is het niet altijd handig om met dergelijke low-level API's te werken. Om ons te concentreren op het zakelijke domein en de wirwar van standaardcode te vermijden, hebben we vaak de ondersteuning nodig van verschillende frameworks en bibliotheken. Atomikos ondersteunt de meeste populaire Java-frameworks gerelateerd aan back-end-integraties. We zullen er hier een paar verkennen.

6.1. Atomikos met lente en Databron

Spring is een van de populaire frameworks in Java die een Inversion of Control (IoC) -container biedt. Het heeft met name ook fantastische ondersteuning voor transacties. Het biedt declaratief transactiebeheer met behulp van Aspect-Oriented Programming (AOP) -technieken.

Spring ondersteunt verschillende transactie-API's, waaronder JTA voor gedistribueerde transacties. We kunnen gebruiken Atomikos als onze JTA-transactiemanager binnen Spring zonder veel moeite. Het belangrijkste is dat onze applicatie dankzij Spring vrijwel agnostisch blijft voor Atomikos.

Laten we eens kijken hoe we ons vorige probleem kunnen oplossen, dit keer door gebruik te maken van Spring. We beginnen met het herschrijven van het Toepassing klasse:

openbare klasse Application {private DataSource inventoryDataSource; privé DataSource orderDataSource; openbare toepassing (DataSource inventoryDataSource, DataSource orderDataSource) {this.inventoryDataSource = inventoryDataSource; this.orderDataSource = orderDataSource; } @Transactional (rollbackFor = Exception.class) public void placeOrder (String productId, int amount) genereert Uitzondering {String orderId = UUID.randomUUID (). ToString (); Verbinding inventoryConnection = inventoryDataSource.getConnection (); Verbinding orderConnection = orderDataSource.getConnection (); Verklaring s1 = inventoryConnection.createStatement (); String q1 = "update inventaris set balance = saldo -" + aantal + "waar productId = '" + productId + "'"; s1.executeUpdate (q1); s1.close (); Verklaring s2 = orderConnection.createStatement (); String q2 = "invoegen in Orders-waarden ('" + orderId + "', '" + productId + "'," + amount + ")"; s2.executeUpdate (q2); s2.close (); inventoryConnection.close (); orderConnection.close (); }}

Zoals we hier kunnen zien, het grootste deel van de transactiegerelateerde boilerplate-code is vervangen door een enkele annotatie op het niveau van de methode. Bovendien zorgt Spring voor instantiëren en injecteren Databron, waarvan onze applicatie afhankelijk is.

Uiteraard moeten we voor Spring relevante configuraties leveren. We kunnen een eenvoudige Java-klasse gebruiken om deze elementen te configureren:

@Configuration @EnableTransactionManagement openbare klasse Config {@Bean (initMethod = "init", destroyMethod = "close") openbare AtomikosDataSourceBean inventoryDataSource () {AtomikosDataSourceBean dataSource = nieuwe AtomikosDataSourceBean (); // Configureer database met ordergegevens retour dataSource; } @Bean (initMethod = "init", destroyMethod = "close") openbare AtomikosDataSourceBean orderDataSource () {AtomikosDataSourceBean dataSource = nieuwe AtomikosDataSourceBean (); // Configureer database met ordergegevens retour dataSource; } @Bean (initMethod = "init", destroyMethod = "close") openbare UserTransactionManager userTransactionManager () gooit SystemException {UserTransactionManager userTransactionManager = nieuwe UserTransactionManager (); userTransactionManager.setTransactionTimeout (300); userTransactionManager.setForceShutdown (true); terug userTransactionManager; } @Bean openbare JtaTransactionManager jtaTransactionManager () gooit SystemException {JtaTransactionManager jtaTransactionManager = nieuwe JtaTransactionManager (); jtaTransactionManager.setTransactionManager (userTransactionManager ()); jtaTransactionManager.setUserTransaction (userTransactionManager ()); retourneer jtaTransactionManager; } @Bean publieke applicatie applicatie () {retourneer nieuwe applicatie (inventoryDataSource (), orderDataSource ()); }}

Hier zijn we aan het configureren AtomikosDataSourceBean voor de twee verschillende databases met onze inventaris- en bestelgegevens. Bovendien bieden we ook de nodige configuratie voor de JTA-transactiebeheerder.

Nu kunnen we onze applicatie testen op transactiegedrag zoals voorheen. Nogmaals, we zouden moeten valideren dat een geldige bestelling ons voorraadsaldo verlaagt, terwijl een ongeldige bestelling het ongewijzigd laat.

6.2. Atomikos met lente, JPA en winterslaap

Hoewel Spring ons tot op zekere hoogte heeft geholpen de standaardcode te verminderen, is het nog steeds behoorlijk uitgebreid. Sommige tools kunnen het werken met relationele databases in Java nog gemakkelijker maken. Java Persistence API (JPA) is een specificatie die het beheer van relationele gegevens in Java-toepassingen beschrijft. Dit vereenvoudigt de gegevenstoegangs- en manipulatiecode in grote mate.

Hibernate is een van de meest populaire implementaties van de JPA-specificatie. Atomikos heeft geweldige ondersteuning voor verschillende JPA-implementaties, inclusief Slaapstand. Net als voorheen blijft onze applicatie agnostisch voor zowel Atomikos als Hibernate, dankzij Spring en JPA!

Laten we eens kijken hoe Spring, JPA en Hibernate kunnen onze applicatie nog beknopter maken en tegelijkertijd de voordelen bieden van gedistribueerde transacties via Atomikos. Net als eerder zullen we beginnen met het herschrijven van het Toepassing klasse:

openbare klasse Applicatie {@Autowired privé InventoryRepository inventoryRepository; @Autowired privé OrderRepository orderRepository; @Transactional (rollbackFor = Exception.class) public void placeOrder (String productId, int amount) gooit SQLException {String orderId = UUID.randomUUID (). ToString (); Inventaris inventaris = inventoryRepository.findOne (productId); inventory.setBalance (inventory.getBalance () - bedrag); inventarisRepository.save (inventaris); Order order = nieuwe order (); order.setOrderId (orderId); order.setProductId (productId); order.setAmount (new Long (amount)); orderRepository.save (bestelling); }}

Zoals we kunnen zien, hebben we nu niet te maken met database-API's op laag niveau. Om deze magie te laten werken, moeten we echter Spring Data JPA-klassen en configuraties configureren. We beginnen met het definiëren van onze domeinentiteiten:

@Entity @Table (name = "INVENTORY") public class Inventory {@Id private String productId; privé Long saldo; // Getters en Setters}
@Entity @Table (name = "ORDERS") openbare klasse Order {@Id private String orderId; private String productId; @Max (5) privé Lang bedrag; // Getters en Setters}

Vervolgens moeten we de opslagplaatsen voor deze entiteiten leveren:

@Repository openbare interface InventoryRepository breidt JpaRepository uit {} @Repository openbare interface OrderRepository breidt JpaRepository uit {}

Dit zijn vrij eenvoudige interfaces, en Spring Data zorgt ervoor dat deze met daadwerkelijke code worden uitgewerkt om met database-entiteiten te werken.

Ten slotte moeten we de relevante configuraties bieden voor een gegevensbron voor zowel voorraad- als orderdatabases en de transactiebeheerder:

@Configuration @EnableJpaRepositories (basePackages = "com.baeldung.atomikos.spring.jpa.inventory", entityManagerFactoryRef = "inventoryEntityManager", transactionManagerRef = "transactionManager") openbare klasse InventoryConfig {@Bean (initMethod = "init", ") openbare AtomikosDataSourceBean inventoryDataSource () {AtomikosDataSourceBean dataSource = nieuwe AtomikosDataSourceBean (); // Configureer de gegevensbron retour dataSource; } @Bean openbare EntityManagerFactory inventoryEntityManager () {HibernateJpaVendorAdapter vendorAdapter = nieuwe HibernateJpaVendorAdapter (); LocalContainerEntityManagerFactoryBean factory = nieuwe LocalContainerEntityManagerFactoryBean (); factory.setJpaVendorAdapter (vendorAdapter); // Configureer de factory return factory.getObject () van de entiteitsbeheerder; }}
@Configuration @EnableJpaRepositories (basePackages = "com.baeldung.atomikos.spring.jpa.order", entityManagerFactoryRef = "orderEntityManager", transactionManagerRef = "transactionManager") openbare klasse OrderConfig {@Bean (initMethod = "init", destroyMethod = "init", vernietigen ") openbare AtomikosDataSourceBean orderDataSource () {AtomikosDataSourceBean dataSource = nieuwe AtomikosDataSourceBean (); // Configureer de gegevensbron retour dataSource; } @Bean openbare EntityManagerFactory orderEntityManager () {HibernateJpaVendorAdapter vendorAdapter = nieuwe HibernateJpaVendorAdapter (); LocalContainerEntityManagerFactoryBean factory = nieuwe LocalContainerEntityManagerFactoryBean (); factory.setJpaVendorAdapter (vendorAdapter); // Configureer de factory return factory.getObject () van de entiteitsbeheerder; }}
@Configuration @EnableTransactionManagement openbare klasse Config {@Bean (initMethod = "init", destroyMethod = "close") openbare UserTransactionManager userTransactionManager () gooit SystemException {UserTransactionManager userTransactionManager = nieuwe UserTransactionManager (); userTransactionManager.setTransactionTimeout (300); userTransactionManager.setForceShutdown (true); terug userTransactionManager; } @Bean openbare JtaTransactionManager transactionManager () gooit SystemException {JtaTransactionManager jtaTransactionManager = nieuwe JtaTransactionManager (); jtaTransactionManager.setTransactionManager (userTransactionManager ()); jtaTransactionManager.setUserTransaction (userTransactionManager ()); retourneer jtaTransactionManager; } @Bean publieke applicatie-applicatie () {retourneer nieuwe applicatie (); }}

Dit is nog heel wat configuratie die we moeten doen. Dit komt gedeeltelijk doordat we Spring JPA configureren voor twee afzonderlijke databases. We kunnen deze configuraties ook verder verkleinen via Spring Boot, maar dat valt buiten het bestek van deze tutorial.

Net als voorheen kunnen we onze applicatie testen op hetzelfde transactiegedrag. Er is deze keer niets nieuws, behalve het feit dat we nu Spring Data JPA met Hibernate gebruiken.

7. Atomikos Beyond JTA

Hoewel JTA uitstekende transactieondersteuning biedt voor gedistribueerde systemen, moeten deze systemen XA-klachten hebben, zoals de meeste relationele databases of berichtenwachtrijen. Echter, JTA is niet nuttig als een van deze systemen de XA-specificatie niet ondersteunt voor een vastlegprotocol in twee fasen. Verschillende bronnen vallen onder deze categorie, vooral binnen een microservices-architectuur.

Verschillende alternatieve protocollen ondersteunen gedistribueerde transacties. Een daarvan is een variatie op het tweefasige commit-protocol dat gebruik maakt van compensaties. Dergelijke transacties hebben een ontspannen isolatiegarantie en staan ​​bekend als op compensatie gebaseerde transacties. Deelnemers committeren de afzonderlijke onderdelen van de transactie in de eerste fase zelf en bieden een compensatiehandler voor een mogelijke rollback in de tweede fase.

Er zijn verschillende ontwerppatronen en algoritmen om een ​​op compensatie gebaseerde transactie te implementeren. Sagas is bijvoorbeeld zo'n populair ontwerppatroon. Ze zijn echter meestal complex om te implementeren en foutgevoelig.

Atomikos biedt een variatie op op compensatie gebaseerde transacties genaamd Try-Confirm / Cancel (TCC). TCC biedt betere zakelijke semantiek aan de entiteiten onder een transactie. Dit is echter alleen mogelijk met geavanceerde architectuurondersteuning van de deelnemers, en TCC is alleen beschikbaar onder het commerciële aanbod van Atomikos, ExtremeTransactions.

8. Alternatieven voor Atomikos

We hebben genoeg van Atomikos meegemaakt om te waarderen wat het te bieden heeft. Bovendien is er een commercieel aanbod van Atomikos met nog krachtigere functies. Atomikos is echter niet de enige optie als het gaat om het kiezen van een JTA-transactiebeheerder. Er zijn een paar andere geloofwaardige opties om uit te kiezen. Laten we eens kijken hoe ze het doen tegen Atomikos.

8.1. Narayana

Narayana is misschien wel een van de oudste open-source gedistribueerde transactiebeheerders en wordt momenteel beheerd door Red Hat. Het wordt op grote schaal gebruikt in de branche, is geëvolueerd door ondersteuning van de gemeenschap en heeft verschillende specificaties en standaarden beïnvloed.

Narayana biedt ondersteuning voor een breed scala aan transactieprotocollen zoals JTA, JTS, Web-Services en REST, om er maar een paar te noemen. Verder kan Narayana worden ingebed in een breed scala aan containers.

In vergelijking met Atomikos biedt Narayana vrijwel alle functies van een gedistribueerde transactiebeheerder. In veel gevallen is Narayana flexibeler te integreren en te gebruiken in applicaties. Narayana heeft bijvoorbeeld taalbindingen voor zowel C / C ++ als Java. Dit gaat echter ten koste van extra complexiteit, en Atomikos is relatief eenvoudiger te configureren en te gebruiken.

8.2. Bitronix

Bitronix is een volledig werkende XA-transactiebeheerder die alle services biedt die vereist zijn voor de JTA API. Belangrijk is dat Bitronix een in te sluiten transactiebibliotheek is die uitgebreide en nuttige foutrapportage en logboekregistratie biedt. Voor een gedistribueerde transactie maakt dit het gemakkelijker om storingen te onderzoeken. Bovendien biedt het uitstekende ondersteuning voor de transactiemogelijkheden van Spring en werkt het met minimale configuraties.

In vergelijking met Atomikos is Bitronix een open-sourceproject en heeft het geen commercieel aanbod met productondersteuning. De belangrijkste functies die deel uitmaken van het commerciële aanbod van Atomikos, maar die in Bitronix ontbreken, zijn onder meer ondersteuning voor microservices en declaratieve elastische schaalbaarheid.

9. Conclusie

Samenvattend hebben we in deze tutorial de basisdetails van transacties doorgenomen. We begrepen wat gedistribueerde transacties zijn en hoe een bibliotheek als Atomikos deze kan vergemakkelijken. Tijdens het proces hebben we de Atomikos API's gebruikt om een ​​eenvoudige applicatie met gedistribueerde transacties te maken.

We begrepen ook hoe Atomikos werkt met andere populaire Java-frameworks en -bibliotheken. Ten slotte hebben we enkele van de alternatieven voor Atomikos besproken die voor ons beschikbaar zijn.

Zoals gewoonlijk is de broncode voor dit artikel te vinden op GitHub.