Programiranje

Distribuirane transakcije spomladi, z XA in brez nje

Čeprav je za distribuirane transakcije spomladi običajno uporabiti Java Transaction API in protokol XA, imate na voljo druge možnosti. Optimalna izvedba je odvisna od vrst virov, ki jih uporablja vaša aplikacija, in od kompromisov, ki ste jih pripravljeni doseči med zmogljivostjo, varnostjo, zanesljivostjo in celovitostjo podatkov. V tej funkciji JavaWorld vas David Syer podjetja SpringSource vodi skozi sedem vzorcev za porazdeljene transakcije v aplikacijah Spring, od tega tri z XA in štiri brez. Raven: srednja

Podpora Spring Framework za Java Transaction API (JTA) omogoča aplikacijam uporabo porazdeljenih transakcij in protokola XA, ne da bi se tekel v vsebniku Java EE. Kljub tej podpori pa je XA drag in je lahko nezanesljiv ali okoren za upravljanje. Torej je lahko dobrodošlo presenečenje, da se lahko določen razred aplikacij popolnoma izogne ​​uporabi XA.

Da boste lažje razumeli premisleke, ki jih vključujejo različni pristopi k porazdeljenim transakcijam, bom analiziral sedem vzorcev obdelave transakcij in zagotovil vzorce kode, ki jih bodo naredili konkretne. Vzorce bom predstavil v obratnem vrstnem redu glede varnosti ali zanesljivosti, začenši s tistimi z najvišjo garancijo celovitosti in atomskosti podatkov v najbolj splošnih okoliščinah. Ko se premikate po seznamu, bo veljalo več opozoril in omejitev. Vzorci so tudi približno v obratnem vrstnem redu stroškov izvajanja (začenši z najdražjimi). Vsi vzorci so v nasprotju s poslovnimi vzorci arhitekturni ali tehnični, zato se ne osredotočam na primer poslovne uporabe, temveč le na minimalno količino kode, da vidim, kako vsak vzorec deluje.

Upoštevajte, da samo prvi trije vzorci vključujejo XA in ti morda ne bodo na voljo ali sprejemljivi zaradi uspešnosti. O vzorcih XA ne razpravljam tako obširno kot o drugih, ker so zajeti drugje, čeprav predstavljam preprost prikaz prvega. Z branjem tega članka boste izvedeli, kaj lahko in česa ne z distribuiranimi transakcijami ter kako in kdaj se izogniti uporabi XA - in kdaj ne.

Porazdeljene transakcije in atomskost

A porazdeljena transakcija je tisti, ki vključuje več kot en transakcijski vir. Primeri transakcijskih virov so priključki za komunikacijo z relacijskimi bazami podatkov in vmesna programska oprema za sporočanje. Pogosto ima tak vir API, ki je videti nekako tako začeti(), povračilo (), zaveži (). V svetu Jave se transakcijski vir običajno prikaže kot produkt tovarne, ki ga zagotavlja osnovna platforma: za bazo podatkov je to Povezava (proizvaja Vir podatkov) ali Java Persistence API (JPA) EntityManager; za Java Message Service (JMS) je Seja.

V tipičnem primeru sporočilo JMS sproži posodobitev baze podatkov. Uspešna interakcija, razčlenjena na časovnico, gre nekako takole:

  1. Začni transakcijo sporočanja
  2. Prejmi sporočilo
  3. Začni transakcijo baze podatkov
  4. Posodobi bazo podatkov
  5. Posreduj transakcijo baze podatkov
  6. Posreduj transakcijo sporočanja

Če bi pri posodobitvi prišlo do napake baze podatkov, kot je kršitev omejitve, bi bilo zaželeno zaporedje videti tako:

  1. Začni transakcijo sporočanja
  2. Prejmi sporočilo
  3. Začni transakcijo baze podatkov
  4. Posodobite bazo podatkov, ne uspe!
  5. Povrni transakcijo baze podatkov
  6. Vrnite transakcijo za pošiljanje sporočil

V tem primeru se sporočilo po zadnjem povratku vrne v vmesno programsko opremo in se v določenem trenutku vrne v drugo transakcijo. To je ponavadi dobro, saj v nasprotnem primeru morda ne boste imeli zapisa, da je prišlo do napake. (Mehanizmi za obravnavo izjem pri samodejnem ponovnem poskusu in obdelavi izjem ne spadajo v področje uporabe tega članka.)

Pomembna značilnost obeh časovnic je, da sta atomska, ki tvori eno logično transakcijo, ki bodisi popolnoma uspe ali popolnoma ne uspe.

Toda kaj zagotavlja, da je časovna premica videti kot eno od teh zaporedij? Izvesti mora se nekaj sinhronizacije med transakcijskimi viri, tako da, če se kdo zaveže, to storita oba in obratno. V nasprotnem primeru celotna transakcija ni atomska. Transakcija je razdeljena, ker gre za več virov in brez sinhronizacije ne bo atomska. Vse tehnične in konceptualne težave pri porazdeljenih transakcijah se nanašajo na sinhronizacijo virov (ali pomanjkanje le-teh).

Prvi trije vzorci, obravnavani spodaj, temeljijo na protokolu XA. Ker so bili ti vzorci široko zajeti, se tu ne bom spuščal v podrobnosti o njih. Tisti, ki poznajo vzorce XA, bodo morda želeli preskočiti na vzorec Shared Transaction Resource.

Poln XA z 2PC

Če potrebujete skoraj neprebojna jamstva, da se bodo transakcije vaše aplikacije obnovile po izpadu, vključno z zrušitvijo strežnika, potem je Full XA vaša edina izbira. Vir v skupni rabi, ki se v tem primeru uporablja za sinhronizacijo transakcije, je poseben upravitelj transakcij, ki koordinira informacije o procesu s protokolom XA. V Javi je z vidika razvijalca protokol izpostavljen prek JTA UserTransaction.

Ker je XA sistemski vmesnik, je ta tehnologija, ki jo večina razvijalcev nikoli ne vidi. Vedeti morajo, da je tam, kaj omogoča, kaj stane in posledice za to, kako uporabljajo transakcijske vire. Stroški izvirajo iz dvofaznega protokola odobritve (2PC), ki ga upravitelj transakcij uporablja za zagotovitev, da se vsi viri dogovorijo o izidu transakcije, preden se konča.

Če je aplikacija omogočena za Spring, uporablja Spring JtaTransactionManager in Spring deklarativno upravljanje transakcij, da skrije podrobnosti osnovne sinhronizacije. Razlika za razvijalca med uporabo XA in neuporabo XA je vse v konfiguraciji tovarniških virov: Vir podatkov in upravljalnik transakcij za aplikacijo. Ta članek vključuje vzorec vloge ( atomikos-db projekt), ki ponazarja to konfiguracijo. The Vir podatkov primerki in upravitelj transakcij so edini elementi aplikacije, specifični za XA ali JTA.

Če želite videti vzorec, ki deluje, zaženite preskusne enote pod com.springsource.open.db. Preprosto MulipleDataSourceTests class samo vstavi podatke v dva vira podatkov in nato uporabi funkcije podpore za integracijo Spring, da vrne transakcijo nazaj, kot je prikazano v seznamu 1:

Seznam 1. Vračilo transakcije

@Transactional @Test public void testInsertIntoTwoDataSources () vrže izjemo {int count = getJdbcTemplate (). Update ("INSERT into T_FOOS (id, name, foo_date) values ​​(?,?, Null)", 0, "foo"); assertEquals (1, count); count = getOtherJdbcTemplate () .update ("INSERT into T_AUDITS (id, operation, name, audit_date) values ​​(?,?,?,?)", 0, "INSERT", "foo", new Date ()); assertEquals (1, štetje); // Spremembe se vrnejo nazaj po izhodu te metode}

Potem MulipleDataSourceTests preveri, ali sta bili operaciji vrnjeni nazaj, kot je prikazano v seznamu 2:

Seznam 2. Preverjanje povračila

@AfterTransaction public void checkPostConditions () {int count = getJdbcTemplate (). QueryForInt ("select count (*) from T_FOOS"); // To spremembo je testni okvir znižal assertEquals (0, count); count = getOtherJdbcTemplate (). queryForInt ("izberite count (*) iz T_AUDITS"); // To se je zavrnilo tudi zaradi XA assertEquals (0, count); }

Za boljše razumevanje, kako deluje upravljanje transakcij Spring in kako ga na splošno konfigurirati, glejte Spring Reference Guide.

XA z 1PC optimizacijo

Ta vzorec je optimizacija, s katero se mnogi upravitelji transakcij izognejo režijskim stroškom 2PC, če transakcija vključuje en vir. Pričakovali bi, da lahko vaš aplikacijski strežnik to ugotovi.

XA in zadnji vir virov

Druga značilnost številnih upraviteljev transakcij XA je, da lahko še vedno zagotavljajo enaka jamstva za izterjavo, če so vsi viri razen enega sposobni XA, kot lahko, kadar so vsi. To storijo z naročanjem virov in uporabo vira, ki ni XA, kot odločilnega glasu. Če ne uspe, se lahko vsi drugi viri premaknejo nazaj. Je skoraj 100-odstotno neprebojen - vendar ni povsem to. In ko ne uspe, ne uspe, ne da bi pustil veliko sledi, razen če se sprejmejo dodatni koraki (kot to počnejo nekatere vrhunske izvedbe).

Vzorec vira transakcijskih virov v skupni rabi

Odličen vzorec za zmanjševanje zapletenosti in povečanje prepustnosti v nekaterih sistemih je, da v celoti odstranimo potrebo po XA, tako da zagotovimo, da so vsi transakcijski viri v sistemu dejansko podprti z istim virom. To očitno ni mogoče v vseh primerih uporabe, vendar je enako trdno kot XA in običajno veliko hitrejše. Vzorec virov skupnih transakcij je neprebojen, vendar je značilen za določene platforme in scenarije obdelave.

Preprost in znan (mnogim) primer tega vzorca je skupna raba baze podatkov Povezava med komponento, ki uporablja objektno-relacijsko preslikavo (ORM) s komponento, ki uporablja JDBC. To se zgodi, če uporabljate upravljavce transakcij Spring, ki podpirajo orodja ORM, kot so Hibernate, EclipseLink in API za obstojnost Java (JPA). Ista transakcija se lahko varno uporablja v komponentah ORM in JDBC, ki jo ponavadi poganja izvedba metode na ravni storitve, kjer je transakcija nadzorovana.

Druga učinkovita uporaba tega vzorca je primer sporočilne posodobitve posamezne baze podatkov (kot v preprostem primeru v uvodu tega članka). Sistemi za vmesno sporočanje sporočil morajo svoje podatke nekje shraniti, pogosto v relacijski bazi podatkov. Za izvedbo tega vzorca je vse, kar je potrebno, sistem za sporočanje usmeriti na isto bazo podatkov, v katero gredo poslovni podatki. Ta vzorec se opira na prodajalca vmesne programske opreme za sporočanje, ki izpostavi podrobnosti svoje strategije shranjevanja, tako da ga je mogoče konfigurirati tako, da kaže na isto bazo podatkov in se priključi na isto transakcijo.

Vsi prodajalci tega ne olajšajo. Druga možnost, ki deluje za skoraj vsako bazo podatkov, je uporaba Apache ActiveMQ za pošiljanje sporočil in vključitev strategije shranjevanja v posrednika sporočil. To je dokaj enostavno konfigurirati, ko poznate trik. To je prikazano v tem članku shared-jms-db vzorčni projekt. Kode aplikacije (v tem primeru enotni testi) se ni treba zavedati, da je ta vzorec v uporabi, ker je vse omogočeno deklarativno v pomladanski konfiguraciji.

Preskus enote v vzorcu SynchronousMessageTriggerAndRollbackTests s sinhronim sprejemom sporočil preveri, ali vse deluje. The testReceiveMessageUpdateDatabase metoda prejme dve sporočili in z njimi vstavi dva zapisa v bazo podatkov. Ko ta metoda zapre, preskusno ogrodje zniža transakcijo, tako da lahko preverite, ali sta sporočila in posodobitve zbirke podatkov nazaj, kot je prikazano v seznamu 3:

Seznam 3. Preverjanje povratnih sporočil in posodobitev baze podatkov

@AfterTransaction public void checkPostConditions () {assertEquals (0, SimpleJdbcTestUtils.countRowsInTable (jdbcTemplate, "T_FOOS")); Seznam seznam = getMessages (); assertEquals (2, list.size ()); }

Najpomembnejše značilnosti konfiguracije so strategija trajanja ActiveMQ, ki sistem sporočil povezuje z istim Vir podatkov kot poslovni podatki in zastava na Spring JmsTemplate za prejemanje sporočil. Seznam 4 prikazuje, kako konfigurirati strategijo trajanja ActiveMQ:

Seznam 4. Konfiguriranje trajnosti ActiveMQ

    ...             

Seznam 5 prikazuje zastavo na pomladi JmsTemplate ki se uporablja za prejemanje sporočil:

Seznam 5. Nastavitev JmsTemplate za transakcijsko uporabo

 ...   

Brez sessionTransacted = true, klici API-ja za transakcije seje JMS nikoli ne bodo izvedeni, sprejema sporočil pa ni mogoče povrniti. Pomembne sestavine tukaj so vdelani posrednik s posebno async = false parameter in ovoj za Vir podatkov ki skupaj zagotavljajo, da ActiveMQ uporablja isti transakcijski JDBC Povezava kot pomlad.

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