Úvod do transakcií v Jave a na jar

1. Úvod

V tomto tutoriále pochopíme, čo sa myslí pod transakciami v Jave. Týmto pochopíme, ako vykonávať miestne transakcie zdrojov a globálne transakcie. To nám tiež umožní preskúmať rôzne spôsoby riadenia transakcií v prostredí Java a Spring.

2. Čo je to transakcia?

Transakcie v Jave, ako je všeobecne, odkazujú na sériu akcií, ktoré musia byť všetky úspešne dokončené. Teda ak jedna alebo viac akcií zlyhá, musia všetky ostatné akcie vycúvať a ponechať stav aplikácie nezmenený. To je nevyhnutné na zabezpečenie toho, aby nikdy nedošlo k narušeniu integrity stavu aplikácie.

Tieto transakcie tiež môžu zahŕňať jeden alebo viac zdrojov, ako je databáza, front správ, čo vedie k rôznym spôsobom vykonávania akcií v rámci transakcie. Patrí sem vykonávanie miestnych transakcií zdrojov s jednotlivými zdrojmi. Prípadne sa na globálnej transakcii môže podieľať viac zdrojov.

3. Zdroje miestnych transakcií

Najskôr preskúmame, ako môžeme používať transakcie v Jave pri práci s jednotlivými zdrojmi. Možno tu máme niekoľko jednotlivých akcií, ktoré vykonávame so zdrojom, ako je databáza. Možno však budeme chcieť, aby sa stali ako jednotný celok, ako nedeliteľná jednotka práce. Inými slovami, chceme, aby sa tieto akcie uskutočňovali v rámci jednej transakcie.

V prostredí Java máme niekoľko spôsobov, ako získať prístup a pracovať s prostriedkom, ako je databáza. Spôsob, akým sa zaoberáme transakciami, preto nie je rovnaký. V tejto časti zistíme, ako môžeme použiť transakcie s niektorými z týchto knižníc v Jave, ktoré sú pomerne často používané.

3.1. JDBC

Pripojenie k databáze Java (JDBC) je API v Jave, ktoré definuje spôsob prístupu k databázam v Jave. Rôzni dodávatelia databáz poskytujú ovládače JDBC na pripojenie k databáze agendickým spôsobom. Takže načítame a Pripojenie z ovládača na vykonávanie rôznych operácií v databáze:

JDBC nám poskytuje možnosti na vykonávanie príkazov v rámci transakcie. The predvolené správanie a Pripojenie je automatické potvrdenie. Na objasnenie to znamená, že s každým jednotlivým príkazom sa zaobchádza ako s transakciou a automaticky sa vykoná ihneď po vykonaní.

Ak však chceme spojiť viac výpisov do jednej transakcie, je možné dosiahnuť aj toto:

Pripojenie pripojenia = DriverManager.getConnection (CONNECTION_URL, USER, PASSWORD); skus {connection.setAutoCommit (false); PreparedStatement firstStatement = pripojenie .prepareStatement ("firstQuery"); firstStatement.executeUpdate (); PreparedStatement secondStatement = pripojenie .prepareStatement ("secondQuery"); secondStatement.executeUpdate (); connection.commit (); } catch (Výnimka e) {connection.rollback (); }

Tu sme deaktivovali režim automatického odovzdávania z Pripojenie. Preto môžeme ručne definovať hranicu transakcie a vykonať a spáchať alebo rollback. JDBC nám tiež umožňuje nastaviť a Savepoint ktorá nám poskytuje väčšiu kontrolu nad tým, koľko sa má vrátiť späť.

3.2. JPA

Java Persistence API (JPA) je špecifikácia v Jave, na ktorú sa dá zvyknúť prekonať priepasť medzi objektovo orientovanými doménovými modelmi a systémami relačných databáz. Existuje teda niekoľko implementácií JPA od tretích strán, ako sú Hibernate, EclipseLink a iBatis.

V JPA môžeme definovať bežné triedy ako Subjekt ktorá im poskytuje trvalú identitu. The EntityManager trieda poskytuje potrebné rozhranie pre prácu s viacerými entitami v rámci perzistencie. Kontext vytrvalosti možno považovať za vyrovnávaciu pamäť prvej úrovne, kde sa spravujú entity:

Kontext vytrvalosti tu môže byť dvoch typov, s rozsahom transakcií alebo s rozšíreným rozsahom. Kontext trvalosti s rozsahom transakcie je viazaný na jednu transakciu. Zatiaľ čo kontext trvalosti s rozšíreným rozsahom sa môže vzťahovať na viaceré transakcie. The predvolený rozsah kontextu perzistencie je rozsah transakcie.

Pozrime sa, ako môžeme vytvoriť EntityManager a definujte hranicu transakcie ručne:

EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory ("jpa-example"); EntityManager entityManager = entityManagerFactory.createEntityManager (); try {entityManager.getTransaction (). begin (); entityManager.persist (firstEntity); entityManager.persist (secondEntity); entityManager.getTransaction (). commit (); } catch (Výnimka e) {entityManager.getTransaction (). rollback (); }

Tu tvoríme EntityManager od EntityManagerFactory v kontexte kontextu perzistencie vymedzeného transakciou. Potom definujeme hranicu transakcie pomocou začať, spáchať, a rollback metódy.

3.3. JMS

Java Messaging Service (JMS) je špecifikácia v Jave, ktorá umožňuje aplikáciám asynchrónne komunikovať pomocou správ. API nám umožňuje vytvárať, posielať, prijímať a čítať správy z frontu alebo témy. Existuje niekoľko služieb zasielania správ, ktoré zodpovedajú špecifikáciám JMS, vrátane OpenMQ a ActiveMQ.

Rozhranie JMS API podporuje spojenie viacerých operácií odosielania alebo prijímania v jednej transakcii. Z povahy integračnej architektúry založenej na správach však výroba a spotreba správy nemôžu byť súčasťou tej istej transakcie. Rozsah transakcie zostáva medzi klientom a poskytovateľom JMS:

JMS nám umožňuje vytvoriť a Session od a Pripojenie ktoré získame od konkrétneho dodávateľa ConnectionFactory. Máme možnosť vytvoriť a Session je transakcia vykonaná alebo nie. Za netransakciu Sessions, môžeme ďalej definovať aj vhodný režim potvrdenia.

Pozrime sa, ako môžeme vytvoriť transakciu Session na odoslanie viacerých správ v rámci transakcie:

ActiveMQConnectionFactory connectionFactory = nová ActiveMQConnectionFactory (CONNECTION_URL); Pripojenie pripojenie = = connectionFactory.createConnection (); connection.start (); try {Session session = connection.createSession (true, 0); Cieľ = cieľ = relácia.createTopic ("TEST.FOO"); MessageProducer producer = session.createProducer (cieľ); producent.send (firstMessage); producent.send (druha sprava); session.commit (); } catch (Výnimka e) {session.rollback (); }

Tu vytvárame MessageProducer pre Destinácia typu témy. Dostaneme Destinácia z Session sme vytvorili skôr. Ďalej používame Session definovať hranice transakcií pomocou metód spáchať a rollback.

4. Globálne transakcie

Ako sme videli, miestne transakcie so zdrojmi nám umožňujú vykonávať viac operácií v rámci jedného zdroja ako zjednoteného celku. Ale dosť často to riešime operácie, ktoré zahŕňajú viac zdrojov. Napríklad prevádzka v dvoch rôznych databázach alebo databáze a fronte správ. Tu nebude pre nás miestna podpora transakcií v rámci zdrojov dostatočná.

To, čo v týchto scenároch potrebujeme, je globálny mechanizmus na vymedzenie transakcií zahŕňajúcich viac zúčastnených zdrojov. Toto sa často nazýva distribuované transakcie a na ich efektívne riešenie sú navrhnuté špecifikácie.

The Špecifikácia XA je jednou z takých špecifikácií, ktorá definuje správcu transakcií na riadenie transakcií s viacerými zdrojmi. Java má celkom vyspelú podporu pre distribuované transakcie zodpovedajúce špecifikácii XA prostredníctvom komponentov JTA a JTS.

4.1. JTA

Java Transaction API (JTA) je rozhranie Java Enterprise Edition API vyvinuté v rámci procesu komunity Java. To umožňuje Java aplikáciám a aplikačným serverom vykonávať distribuované transakcie medzi prostriedkami XA. JTA je modelovaný na architektúre XA a využíva dvojfázové odovzdanie.

JTA špecifikuje štandardné rozhrania Java medzi správcom transakcií a ostatnými stranami v distribuovanej transakcii:

Poďme pochopiť niektoré kľúčové rozhrania zvýraznené vyššie:

  • TransactionManager: Rozhranie, ktoré umožňuje aplikačnému serveru vymedziť a riadiť transakcie
  • UserTransaction: Toto rozhranie umožňuje aplikačnému programu výslovne vymedziť a riadiť transakcie
  • XAResource: Účelom tohto rozhrania je umožniť správcovi transakcií pracovať so správcami prostriedkov pre prostriedky kompatibilné s XA

4.2. JTS

Transakčná služba Java (JTS) je špecifikácia pre budovanie manažéra transakcií, ktorá sa mapuje na špecifikáciu OMG OTS. Spoločnosť JTS používa na šírenie kontextu transakcií medzi správcami transakcií JTS štandardné rozhrania CORBA ORB / TS a internetový protokol Inter-ORB (IIOP).

Na vysokej úrovni podporuje rozhranie Java Transaction API (JTA). Správca transakcií JTS poskytuje transakčné služby stranám zapojeným do distribuovanej transakcie:

Služby, ktoré JTS poskytuje aplikácii, sú do značnej miery transparentné, a preto si ich v architektúre aplikácie ani nemusíme všimnúť. JTS je postavený na aplikačnom serveri, ktorý abstrahuje všetku sémantiku transakcií z aplikačných programov.

5. Správa transakcií JTA

Teraz je čas pochopiť, ako môžeme riadiť distribuovanú transakciu pomocou JTA. Distribuované transakcie nie sú triviálne riešenia, a preto majú tiež dôsledky na náklady. Navyše, Existuje niekoľko možností, z ktorých si môžeme vybrať, či zahrnieme JTA do našej aplikácie. Preto musí byť naša voľba z hľadiska celkovej aplikačnej architektúry a ašpirácií.

5.1. JTA v aplikačnom serveri

Ako sme už videli skôr, na architektúru JTA sa spolieha aplikačný server na uľahčenie množstva operácií súvisiacich s transakciami. Jednou z kľúčových služieb, ktoré sa spolieha na to, že server poskytuje, je služba pomenovania prostredníctvom JNDI. To je miesto, kde sú zdroje XA, ako sú zdroje údajov, viazané a načítané z nich.

Okrem toho máme na výber, ako chceme v našej aplikácii spravovať hranicu transakcie. To vedie k dvom typom transakcií v rámci aplikačného servera Java:

  • Transakcia spravovaná kontajnerom: Ako už názov napovedá, tu je hranica transakcie nastavená aplikačným serverom. To zjednodušuje vývoj Enterprise Java Beans (EJB), pretože nezahŕňa príkazy týkajúce sa vymedzenia transakcií a spolieha sa na to výlučne v kontajneri. To však neposkytuje aplikácii dostatočnú flexibilitu.
  • Transakcia spravovaná fazuľou: Na rozdiel od transakcie spravovanej kontajnerom, v transakcii spravovanej fazuľou EJB obsahujú výslovné príkazy na vymedzenie vymedzenia transakcie. To poskytuje aplikácii presnú kontrolu pri označovaní hraníc transakcie, aj keď za cenu zložitosti.

Jednou z hlavných nevýhod vykonávania transakcií v kontexte aplikačného servera je to, že aplikácia je pevne spojená so serverom. To má dôsledky na testovateľnosť, spravovateľnosť a prenosnosť aplikácie. Toto je hlbšie v architektúre mikroslužieb, kde sa kladie väčší dôraz na vývoj serverovo neutrálnych aplikácií.

5.2. Samostatné JTA

Problémy, o ktorých sme hovorili v poslednej časti, priniesli obrovský impulz k vytváraniu riešenia pre distribuované transakcie, ktoré sa nespoliehajú na aplikačný server. V tejto súvislosti máme k dispozícii niekoľko možností, napríklad použitie podpory transakcií s Spring alebo použitie správcu transakcií ako Atomikos.

Pozrime sa, ako môžeme použiť manažéra transakcií, ako je Atomikos, na uľahčenie distribuovanej transakcie s databázou a frontom správ. Jedným z kľúčových aspektov distribuovanej transakcie je získanie a vyradenie zúčastnených zdrojov z monitorovania transakcií. Atomikos sa o to stará za nás. Všetko, čo musíme urobiť, je použiť abstrakcie poskytnuté Atomikos:

AtomikosDataSourceBean atomikosDataSourceBean = nový AtomikosDataSourceBean (); atomikosDataSourceBean.setXaDataSourceClassName ("com.mysql.cj.jdbc.MysqlXADataSource"); DataSource dataSource = atomikosDataSourceBean;

Tu vytvárame inštanciu AtomikosDataSourceBean a registrácia konkrétneho dodávateľa XADataSource. Od tejto chvíle môžeme pokračovať v používaní ako ktokoľvek iný Dátový zdroj a získate výhody distribuovaných transakcií.

Podobne aj my mať abstrakciu pre front správ ktorá sa stará o automatickú registráciu zdroja XA špecifického pre dodávateľa s monitorom transakcií:

AtomikosConnectionFactoryBean atomikosConnectionFactoryBean = nový AtomikosConnectionFactoryBean (); atomikosConnectionFactoryBean.setXaConnectionFactory (nový ActiveMQXAConnectionFactory ()); ConnectionFactory connectionFactory = atomikosConnectionFactoryBean;

Tu vytvárame inštanciu AtomikosConnectionFactoryBean a registrácia XAConnectionFactory od dodávateľa JMS s povoleným XA. Potom to môžeme naďalej používať ako bežné ConnectionFactory.

Teraz nám Atomikos poskytuje posledný kúsok skladačky, ktorý spája všetko, príklad UserTransaction:

UserTransaction userTransaction = nový UserTransactionImp ();

Teraz sme pripravení vytvoriť aplikáciu s distribuovanými transakciami v celej našej databáze a vo fronte správ:

try {userTransaction.begin (); java.sql.Connection dbConnection = dataSource.getConnection (); PreparedStatement ReadyStatement = dbConnection.prepareStatement (SQL_INSERT); readyStatement.executeUpdate (); javax.jms.Connection mbConnection = connectionFactory.createConnection (); Relácia session = mbConnection.createSession (true, 0); Cieľový cieľ = session.createTopic ("TEST.FOO"); MessageProducer producer = session.createProducer (cieľ); producent.send (SPRÁVA); userTransaction.commit (); } catch (Výnimka e) {userTransaction.rollback (); }

Tu používame metódy začať a spáchať v triede UserTransaction na vymedzenie hranice transakcie. To zahŕňa uloženie záznamu do databázy a tiež publikovanie správy do frontu správ.

6. Podpora transakcií na jar

Videli sme to spracovanie transakcií je skôr zahrnutá úloha, ktorá zahŕňa veľa štandardizovaného kódovania a konfigurácie. Každý zdroj má navyše svoj vlastný spôsob spracovania miestnych transakcií. V Jave nás JTA abstrahuje od týchto variácií, ale ďalej prináša podrobnosti špecifické pre poskytovateľa a zložitosť aplikačného servera.

Jarná plošina poskytuje oveľa čistejší spôsob vybavovania transakcií, tak miestnych, ako aj globálnych transakcií v Jave. To spolu s ďalšími výhodami Springu vytvára presvedčivý prípad pre použitie Springu na spracovanie transakcií. Okrem toho je celkom ľahké nakonfigurovať a prepnúť správcu transakcií pomocou aplikácie Spring, ktorá môže byť poskytovaná serverom alebo samostatná.

Jar nám to poskytuje bezproblémovú abstrakciu vytvorením proxy pre dané metódy s transakčným kódom. Proxy riadi stav transakcie v mene kódu pomocou TransactionManager:

Centrálne rozhranie tu je PlatformTransactionManager ktorá má k dispozícii množstvo rôznych implementácií. Poskytuje abstrakcie nad JDBC (DataSource), JMS, JPA, JTA a mnohými ďalšími zdrojmi.

6.1. Konfigurácie

Pozrime sa, ako to môžeme nakonfigurovať Na jar používať Atomikos ako správcu transakcií a poskytovať transakčnú podporu pre JPA a JMS. Začneme definovaním a PlatformTransactionManager typu JTA:

@Bean public PlatformTransactionManager platformTransactionManager () hodí Throwable {return new JtaTransactionManager (userTransaction (), transactionManager ()); }

Tu poskytujeme inštancie UserTransaction a TransactionManager do JTATransactionManager. Tieto inštancie poskytuje knižnica správcov transakcií, ako je Atomikos:

@Bean public UserTransaction userTransaction () {return new UserTransactionImp (); } @Bean (initMethod = "init", destruMethod = "zavrieť") public TransactionManager transactionManager () {vrátiť nový UserTransactionManager (); }

Triedy UserTransactionImp a UserTransactionManager poskytuje Atomikos tu.

Ďalej musíme definovať JmsTemplete ktorá základná trieda umožňujúca synchrónny prístup JMS na jar:

@Bean public JmsTemplate jmsTemplate () hodí Throwable {return new JmsTemplate (connectionFactory ()); }

Tu, ConnectionFactory poskytuje Atomikos, kde umožňuje distribuovanú transakciu pre doménu Pripojenie poskytuje:

@Bean (initMethod = "init", destruMethod = "zavrieť") verejné ConnectionFactory connectionFactory () {ActiveMQXAConnectionFactory activeMQXAConnectionFactory = nový ActiveMQXAConnectionFactory (); activeMQXAConnectionFactory.setBrokerURL ("tcp: // localhost: 61616"); AtomikosConnectionFactoryBean atomikosConnectionFactoryBean = nový AtomikosConnectionFactoryBean (); atomikosConnectionFactoryBean.setUniqueResourceName ("xamq"); atomikosConnectionFactoryBean.setLocalTransactionMode (false); atomikosConnectionFactoryBean.setXaConnectionFactory (activeMQXAConnectionFactory); návrat atomikosConnectionFactoryBean; }

Ako teda vidíme, tu uvádzame informácie o konkrétnom poskytovateľovi JMS XAConnectionFactory s AtomikosConnectionFactoryBean.

Ďalej musíme definovať AbstractEntityManagerFactoryBean ktorý je zodpovedný za vytvorenie JPA EntityManagerFactory fazuľa na jar:

@Bean public LocalContainerEntityManagerFactoryBean entityManager () hodí SQLException {LocalContainerEntityManagerFactoryBean entityManager = nový LocalContainerEntityManagerFactoryBean (); entityManager.setDataSource (dataSource ()); Vlastnosti vlastnosti = nové Vlastnosti (); properties.setProperty ("javax.persistence.transactionType", "jta"); entityManager.setJpaProperties (vlastnosti); návrat entityManager; }

Rovnako ako predtým, Dátový zdroj ktoré sme nastavili v LocalContainerEntityManagerFactoryBean tu poskytuje Atomikos s povolenými distribuovanými transakciami:

@Bean (initMethod = "init", destruMethod = "zavrieť") public DataSource dataSource () vyvolá SQLException {MysqlXADataSource mysqlXaDataSource = nový MysqlXADataSource (); mysqlXaDataSource.setUrl ("jdbc: mysql: //127.0.0.1: 3306 / test"); AtomikosDataSourceBean xaDataSource = nový AtomikosDataSourceBean (); xaDataSource.setXaDataSource (mysqlXaDataSource); xaDataSource.setUniqueResourceName ("xads"); návrat xaDataSource; }

Aj tu uvádzame konkrétne informácie o poskytovateľovi XADataSource v AtomikosDataSourceBean.

6.2. Správa transakcií

Keď sme prešli všetkými konfiguráciami v poslednej časti, musíme sa cítiť dosť ohromení! Nakoniec by sme mohli spochybniť výhody plynúce z využívania jari. Pamätajte však, že celá táto konfigurácia má nám umožnil abstrakciu od väčšiny štandardných platforiem špecifických pre poskytovateľa a náš skutočný kód aplikácie si toho vôbec nemusí byť vedomý.

Takže teraz sme pripravení preskúmať, ako využiť transakcie na jar, kde máme v úmysle aktualizovať databázu a publikovať správy. Jar nám poskytuje dva spôsoby, ako to dosiahnuť pomocou ich vlastných výhod, z ktorých si môžeme vybrať. Poďme pochopiť, ako ich môžeme využiť:

  • Deklaratívna podpora

Najjednoduchší spôsob použitia transakcií na jar je pomocou deklaratívnej podpory. Tu máme pohodlná anotácia, ktorá je k dispozícii pri metóde alebo dokonca na hodine. Toto jednoducho umožňuje globálnu transakciu pre náš kód:

@PersistenceContext EntityManager entityManager; @Autowired JmsTemplate jmsTemplate; @Transactional (propagation = Propagation.REQUIRED) public void process (ENTITY, MESSAGE) {entityManager.persist (ENTITY); jmsTemplate.convertAndSend (DESTINATION, MESSAGE); }

Jednoduchý vyššie uvedený kód je dostatočný na to, aby umožnil operáciu uloženia v databáze a operáciu publikovania vo fronte správ v rámci transakcie JTA.

  • Programová podpora

Aj keď je deklaratívna podpora celkom elegantná a jednoduchá, neponúka nám výhoda presnejšej kontroly hranice transakcie. Ak teda máme určitú potrebu toho dosiahnuť, Spring ponúka programovú podporu na vymedzenie hranice transakcie:

@Autowired private PlatformTransactionManager transactionManager; public void process (ENTITY, MESSAGE) {TransactionTemplate transactionTemplate = new TransactionTemplate (transactionManager); transactionTemplate.executeWithoutResult (status -> {entityManager.persist (ENTITY); jmsTemplate.convertAndSend (DESTINATION, MESSAGE);}); }

Ako teda vidíme, musíme vytvoriť TransactionTemplate s dostupnými PlatformTransactionManager. Potom môžeme použiť TransactionTemplete spracovať kopu výpisov v rámci globálnej transakcie.

7. Následné úvahy

Ako sme videli, spracovanie transakcií, najmä transakcií, ktoré zahŕňajú viac zdrojov, je zložité. Navyše, transakcie vo svojej podstate blokujú, čo je škodlivé pre latenciu a priepustnosť žiadosti. Ďalej nie je ľahké testovať a udržiavať kód s distribuovanými transakciami, najmä ak transakcia závisí od základného aplikačného servera. Celkovo teda je najlepšie vyhnúť sa transakciám, pokiaľ môžeme!

Ale to je ďaleko od reality. Stručne povedané, v aplikáciách v reálnom svete často máme oprávnenú potrebu transakcií. Aj keď je je možné prehodnotiť architektúru aplikácie bez transakcií, nemusí to byť vždy možné. Preto musíme pri práci s transakciami v prostredí Java prijímať určité osvedčené postupy, aby sme zlepšili naše aplikácie:

  • Jedným zo základných posunov, ktoré by sme mali prijať, je namiesto správ poskytovaných aplikačným serverom používať samostatných správcov transakcií. Toto samotné môže našu aplikáciu výrazne zjednodušiť. Okrem toho je veľmi vhodný pre architektúru mikroslužieb natívnej pre cloud.
  • Ďalej abstrakčná vrstva, ako je jar, nám môže pomôcť zvládnuť priamy dopad poskytovateľov ako poskytovatelia JPA alebo JTA. To nám teda môže umožniť prepínanie medzi poskytovateľmi bez veľkého vplyvu na našu obchodnú logiku. Navyše nám to berie zodpovednosť za správu stavu transakcie na nízkej úrovni.
  • Nakoniec by sme mali byť pri výbere hranice transakcie v našom kóde buďte opatrní. Pretože transakcie blokujú, je vždy lepšie udržiavať hranicu transakcií čo najviac obmedzenú. Ak je to potrebné, mali by sme pri transakciách uprednostniť programovú kontrolu pred deklaratívnou.

8. Záver

Ak to zhrnieme, v tomto tutoriáli sme diskutovali o transakciách v kontexte Java. Prešli sme podporou jednotlivých lokálnych transakcií zdrojov v Jave pre rôzne zdroje. Prešli sme si tiež spôsobmi, ako dosiahnuť globálne transakcie v Jave.

Ďalej sme prešli rôznymi spôsobmi riadenia globálnych transakcií v Jave. Tiež sme pochopili, ako nám Spring uľahčuje používanie transakcií v Jave.

Nakoniec sme si prešli niektoré z najlepších postupov pri práci s transakciami v prostredí Java.


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