Transaksionet
Një transaksion quhet një sekuencë operacionesh mbi të dhëna që ka një fillim dhe një fund.
Transaksioni është ekzekutimi i renditur i operacioneve të leximit dhe shkruarjes. Përfundimi i transaksionit mund të jetë ose ruajtja e ndryshimeve (komitimi, commit) ose anulimi i ndryshimeve (ripelodhja, rollback). Në lidhje me databazat, transaksioni përfshin disa kërkesa, të cilat interpretohen si një kërkesë e vetme.
Transaksionet duhet të përmbushin pronat ACID.
Atohem. Një transaksion ose kryhet plotësisht ose nuk kryhet fare.
Konsistenca. Në përfundim të transaksionit, nuk duhet të shkelet asnjë kufizim i vendosur mbi të dhënat (p.sh. constraints në databazë). Konsistenca do të thotë që sistemi do të kalojë nga një gjendje e saktë në një tjetër gjendje të saktë.
Izolimi. Transaksionet që ekzekutohen paralelisht nuk duhet të ndikojnë njëra-tjetrën, p.sh. të ndryshojnë të dhënat që përdor një tjetër transaksion. Rezultati i ekzekutimit të transaksioneve paralelisht duhet të jetë njësoj si nëse transaksionet do të ekzekutoheshin rendësisht.
Qëndrueshmëria. Pas komitimit, ndryshimet nuk duhet të humben.
Ditaari i Transaksioneve.
Ditaari ruan ndryshimet e kryera nga transaksionet, siguron atomaritetin dhe qëndrueshmërinë e të dhënave në rast dështimi të sistemit.
Ditaari përmban vlerat që të dhënat kishin para dhe pas ndryshimit nga transaksioni. Strategjia e shkallëzimit të avancuar obligon shtimin e një regjistrimi në ditar për vlerat e mëparshme përpara fillimit, dhe për ato përfundimtare pas përfundimit të transaksionit. Në rast të ndaljes së papritur të sistemit të databazës, kjo lexon ditarin në rend të kundërt dhe anullon ndryshimet e bëra nga transaksionet. Kur has një transaksion të ndërprerë, databaza e kryen atë dhe e regjistron ndryshimin në ditar. Duke qenë në gjendjen e momentit të dështimit, databaza lexon ditarin në rend të drejtpërdrejtë dhe rikthen ndryshimet e bëra nga transaksionet. Kështu ruhet qëndrueshmëria e transaksioneve që tashmë janë komituar dhe atomariteti i transaksionit të ndërprerë.
Përsëritja e thjeshtë e transaksioneve me gabime nuk është e mjaftueshme për rikuperim.
Shembull. Në llogarinë e përdoruesit ka 500$ dhe përdoruesi vendos të tërheqë ato përmes një bankomati. Kryhen dy transaksione. E para lexon vlerën e bilancit dhe nëse ka mjaft fonde, i jep paratë përdoruesit. E dyta heq nga bilanci shumën e nevojshme. Supozoni se ndodhi një defekt i sistemit dhe operacioni i parë nuk u realizua, ndërsa i dyti u realizua. Në këtë rast, ne nuk mund ta japim përsëri paratë përdoruesit pa e kthyer sistemin në gjendjen e tij fillestare me një bilanc pozitiv.
Niveli i izolimit
Leximi i të dhënave të fikshuara (Read Committed)
Problemi i leximit të ndotur (Dirty Read) qëndron në faktin se një transaksion mund të lexojë rezultatin përkohësisht të një transaksioni tjetër.
Shembull. Vlera fillestare e bilancit është 0$. T1 shton 50$ në bilanc. T2 lexon vlerën e bilancit (50$). T1 anulon ndryshimet dhe përfundon. T2 vazhdon me ekzekutimin duke poseduar të dhëna të pasakta për bilancin.
Zgjidhja është leximi i të dhënave të fikshuara (Read Committed) që ndalon leximin e të dhënave të ndryshuara nga një transaksion. Nëse transaksioni A ndryshon një grup të dhënash, atëherë transaksioni B kur kërkon këto të dhëna është i detyruar të presë për përfundimin e transaksionit A.
Leximi i përsëritur (Repeatable Read)
Problemi i ndryshimeve të humbura (Lost Updates). T1 ruan ndryshimet mbi ndryshimet e T2.
Shembull. Vlera fillestare e bilancit është 0$ dhe dy transaksione e plotësojnë bilancin njëkohësisht. T1 dhe T2 lexojnë bilancin e barabartë me 0$. Më pas T2 shton 200$ në 0$ dhe ruan rezultatin. T1 shton 100$ në 0$ dhe ruan rezultatin. Rezultati përfundimtar është 100$ në vend të 300$.
Problemi i leximit të papërsëritshëm (Unrepeatable read). Leximi i njëjtave të dhëna përsëri kthen vlera të ndryshme.
Shembull. T1 lexon vlerën e bilancit që është 0$. Më pas T2 shton 50$ në bilanc dhe përfundon. T1 lexon të dhënat përsëri dhe zbulon një mos përputhje me rezultatin e mëparshëm.
Leximi i përsëritur (Repeatable Read) garanton që leximi përsëri do të kthejë të njëjtin rezultat. Të dhënat e lexuara nga një transaksion nuk lejohen të ndryshohen nga të tjera deri në përfundimin e transaksionit. Nëse transaksioni A lexon një grup të dhënash, atëherë transaksioni B kur i drejtohet këtyre të dhënave është i detyruar të presë për përfundimin e transaksionit A.
Leximi i renditur (Serializable)
Problemi i leximit fantazmë (Phantom Reads). Dy kërkesa që zgjedhin të dhëna sipas një kushti çojnë në rezultate të ndryshme.
Shembulli. T1 kërkon numrin e të gjitha përdoruesve të cilët kanë një bilanc mbi 0$ por nën 100$. T2 heq 1$ nga përdoruesi me një bilanc prej 101$. T1 ekzekuton përsëri kërkesën.
Leximi i renditur (Serializable). Transaksionet ekzekutohen si plotësisht të renditura. Ndalohet përditësimi dhe shtimi i regjistrimeve që bien nën kushtet e kërkesës. Nëse transaksioni A ka kërkuar të dhënat e të gjithë tabelës, atëherë tabela e tërë ngrihet për transaksionet e tjera deri në përfundimin e transaksionit A.
Planifikuesi (Scheduler)
Vendos rendin në të cilin duhen ekzekutuar operacionet kur transaksionet ndodhin njëkohësisht.
Siguron nivelin e caktuar të izolimit. Nëse rezultati i ekzekutimit të operacioneve nuk varet nga rendi i tyre, atëherë këto operacione janë komutative (Permutable). Operacionet e leximit dhe operacionet mbi të dhëna të ndryshme janë komutative. Operacionet e leximit-shkruaj dhe shkruaj-shkruaj nuk janë komutative. Detyra e planifikuesit është të alternojë operacionet e kryera nga transaksionet paralele, në mënyrë që rezultati të jetë ekuivalent me ekzekutimin e renditur të transaksioneve.
Mekanizmat e kontrollit të detyrave paralele (Concurrency Control)
Optimistike bazuar në zbulimin dhe zgjidhjen e konflikteve, pesimiste në parandalimin e shfaqjes së konflikteve.
Me qasjen optimiste, disa përdorues marrin kopje të të dhënave. I pari që përfundon redaktimin ruan ndryshimet, ndërsa të tjerët duhet të realizojnë një bashkim të ndryshimeve. Algoritmi optimist lejon që konflikti të ndodhë, por sistemi duhet të rikuperohet pas konfliktit.
Me qasjen pesimiste, përdoruesi i pari që kap të dhënat pengon të tjerët nga marrja e të dhënave. Nëse konfliktet janë të rralla, është разумно të zgjidhni strategjinë optimiste, pasi ajo siguron një nivel më të lartë paralelizmi.
Bllokimi (Locking)
Nëse një transaksion ka bllokuar të dhënat, atëherë transaksionet e tjera që kërkojnë qasje në të dhënat duhet të presin përshkallëzimin.
Një bllok mund të vendoset mbi një bazë të dhënash, një tabelë, një rresht ose një atribut. Bllokimi i përbashkët (Shared Lock) mund të vendoset mbi të njëjtat të dhëna nga disa transaksione, duke lejuar të gjitha transaksionet (përfshirë atë që ka vendosur bllokimin) të lexojnë, por ndalon ndryshimin dhe bllokimin monopol. Bllokimi monopol (Exclusive Lock) mund të vendoset vetëm nga një transaksion, duke lejuar çdo veprim të transaksionit që e ka vendosur atë, duke ndaluar çdo veprim për të tjerët.
Një ndërlikim i ndërsjellë konsiderohet një situatë kur transaksionet janë në pritje, që zgjat pafundësisht.
Shembulli. Transaksioni i parë pret çlirimin e të dhënave të kapura nga i dyti, ndërsa i dyti pret çlirimin e të dhënave të kapura nga i pari.
Zgjidhja optimiste për problemin e ndërlikimeve lejon që ndërlikimi të ndodhë, por pastaj e rikthen sistemin duke rrokullisur një nga transaksionet që përfshihen në ndërlikim.
Me një periudhë të caktuar bëhet kërkimi për ndërlikime. Një nga mënyrat e zb发现jes është sipas kohës, dmth të mendohet se ndërlikimi ka ndodhur nëse një transaksion është duke u ekzekutuar shumë gjatë. Kur ndërlikimi zbulohet, një nga transaksionet rikthehet, duke lejuar që transaksionet e tjera që marrin pjesë në ndërlikim të përfundojnë. Zgjedhja e viktimës mund të bazohet në koston e transaksioneve ose në mosmarrëveshjen e tyre (Skemat Wait-Die dhe Wound-wait).
Çdo transaksion T i jepet një markë kohore TS e cila përmban kohën e fillimit të ekzekutimit të transaksionit.
Wait-Die.
Nëse TS(Ti) < TS(Tj), nuk është e nevojshme, madje, ajo jep një gabim sintaksor Ti pret, përndryshe Ti rikthehet dhe fillon sërish me të njëjtën markë kohore.
Nëse një transaksion më i ri ka kapur një burim, dhe një më i vjetër kërkon të njëjtin burim, atëherë transaksionit më të vjetër i lejohet të pret. Nëse transaksioni më i vjetër ka kapur burimin, atëherë transaksioni më i ri që kërkon këtë burim do të rikthehet.
Wound-wait.
Nëse TS(Ti) < TS(Tj), nuk është e nevojshme, madje, ajo jep një gabim sintaksor Tj rikthehet dhe fillon sërish me të njëjtën markë kohore, përndryshe Ti pret.
Nëse një transaksion më i ri ka kapur një burim, dhe një transaksion më i vjetër kërkon të njëjtin burim, atëherë transaksioni më i ri do të anulohet. Nëse një transaksion më i vjetër ka kapur një burim, atëherë transaksioni më i ri, që kërkon këtë burim, i lejohet të presë. Zgjedhja e viktimës bazuar në moshën parandalon shfaqjen e bllokimeve, por anullon transaksionet që nuk janë në një gjendje bllokimi. Problemi është se transaksionet mund të anullohen shumë herë, pasi një transaksion më i vjetër mund të mbajë për një kohë të gjatë burimin.
Zgjidhja pesimiste e problemit të bllokimeve nuk lejon që transaksioni të fillojë ekzekutimin nëse ka rrezik të shfaqjes së bllokimit.
Për të zbuluar bllokimin, ndërtohet një grafik (grafiku i pritjes, wait-for-graph), në të cilin kulmet janë transaksionet, dhe skajet janë të drejtuara nga transaksionet që presin të lirojnë të dhënat te transaksioni që ka kapur këto të dhëna. Kjo konsiderohet një bllokim të ketë ndodhur, nëse grafiku ka cikle. Ndërtimi i grafikut të pritjes, veçanërisht në DB të shpërndara, është një procedurë e shtrenjtë.
Bllokimi dyfazor — parandalimi i bllokimeve përmes kapjes së të gjithë burimeve të përdorura nga transaksioni në fillim të tij dhe lirohet në fund.
Të gjitha operacionet që bllokojnë duhet të parandalojnë të parën që lirohet. Ka dy faza — Faza e Rritjes, ku ndodh grumbullimi i kapjeve dhe Faza e Paksimit, ku ndodh lirimi i kapjeve. Nëse kapja e njërit prej burimeve është e pamundur, transaksioni fillon nga e para. Ka situata kur transaksioni nuk mund të kapë burimet e nevojshme, për shembull, nëse disa transaksione po garojnë për të njëjtat burime.
Komiti dyfazor siguron përfundimin e komitit në të gjitha kopjet e DB.
Çdo DB regjistron informacionin mbi të dhënat që do të ndryshohen në log dhe i përgjigjet koordinatorit me OK (Faza e Votimit). Pas që të gjithë kanë përgjigjur me OK, koordinatori dërgon një sinjal që detyron të gjithë të kryejnë komitin. Pas komitit, сервера përgjigjen me OK; nëse ndonjë nuk përgjigjet me OK, atëherë koordinatori dërgon një sinjal anullimi të ndryshimeve për të gjitha serverët (Faza e Përfundimit).
Metoda e shënjave të kohës.
Një transaksion më i vjetër anullohet kur përpiqet të aksesojë të dhënat që janë angazhuar nga një transaksion më i ri.
Çdo transaksioni i jepet një shenjë temporale TS përkatëse me kohën e fillimit të ekzekutimit. Nëse Ti është më e vjetër Tj, nuk është e nevojshme, madje, ajo jep një gabim sintaksor TS(Ti) < TS(Tj).
Kur transaksioni rikthehet, i jepet një shenjë temporale e re. Çdo objekt të dhënash Q i përfshirë në transaksion etiketizohet me dy shenja. W-TS(Q) — shenja temporale e transaksionit më të ri, i cili ka kryer me sukses një shkruar Q. R-TS(Q) — shenja temporale e transaksionit më të ri, i cili ka kryer një lexues mbi Q.
Kur transaksioni T kërkon të lexojë të dhënat Q janë dy mundësi.
Nëse TS(T) < W-TS(Q), nëse të dhënat janë azhurnuar nga një transaksion më i ri, atëherë transaksioni T rikthehet.
Nëse TS(T) >= W-TS(Q), atëherë leximi kryhet dhe R-TS(Q) është MAX(R-TS(Q), TS(T)).
Kur transaksioni T kërkon ndryshimin e të dhënave Q janë dy mundësi.
Nëse TS(T) < R-TS(Q), pra, të dhënat tashmë janë lexuar nga një transaksion më i ri dhe nëse bëhet ndryshimi, do të ketë një konflikt. Transaksioni T rikthehet.
Nëse TS(T) < W-TS(Q), pra, transaksioni përpiqet të rishkruajë një vlerë më të re, transaksioni T rikthehet. Në raste të tjera, ndryshimi kryhet dhe W-TS(Q) bëhet e barabartë me TS(T).
Nuk kërkohet ndërtimi i shtrenjtë i një grafiku pritjeje. Transaksionet më të vjetra varen nga më të rinjtë, për rrjedhojë në grafikun e pritjeve nuk ka cikle. Nuk ka bllokime të ndërsjellta, pasi transaksionet nuk presin, por rikthehen menjëherë. Mund të ndodhin rikthime kaskadë. Nëse Ti u rikthye, dhe Tj lexoi të dhënat që e ndryshoi Ti, nuk është e nevojshme, madje, ajo jep një gabim sintaksor Tj duhet gjithashtu të rikthehet. Nëse gjatë kësaj Tj është bërë commit, do të ketë një shkelje të parimit të qëndrueshmërisë.
Një nga zgjidhjet për rikthimet kaskadë. Transaksioni kryen të gjitha operacionet e shkruar në fund, duke obliguar transaksionet e tjera të presin për përfundimin e kësaj operacione. Transaksionet presin për commit përpara leximit.
Rregulli i shkrimit të Thomas — një variacion i metodës së shenjave temporale në të cilën të dhënat e azhurnuara nga një transaksion më i ri ndalohen të rishkruhen nga një më të vjetër
Transaksioni T kërkon ndryshimin e të dhënave Q. Nëse TS(T) < W-TS(Q), pra, transaksioni përpiqet të rishkruajë një vlerë më të re, transaksioni T nuk rikthehet si në metodën e shenjave temporale.
Burimi: habr.com
