Tranzakciók ------------ Részletesebb infók a doksiban -> Application Developers' Guide 2. fejezet A tranzakcióktól általában elvárt tulajdonságok: A - atomosság (az adatbáziskezelő garantálja) C - konzisztencia megőrzése (a programozó feladata) I - elkülönítés (több szintjét is támogatja általában egy rendszer) D - tartósság (a rendszer garantálja a helyreállító módszereivel) S - sorolhatóság (a gyakorlatban sokszor túl szigorúnak tűnik) Három olyan probléma, amelyek a gyakorlatban előfordulhatnak: 1. Piszkos adatok olvasása Még nem commitált adatokat olvas egy tranzakció. 2. Nem ismételhető lekérdezés Egy lekérdezés újabb futásakor időközben módosított (és commitált) sorokat olvas. 3. Fantom sorok olvasása Egy lekérdezés ismételt futtatása olyan sorokat is talál, amelyek előzőleg még nem léteztek. A fenti problémáknak megfelelően az SQL szabvány 4 elkülönítési szintet definiál, amelyek a fenti esetek közül egyre kevesebbnek az előfordulását engedik meg. Ezek az alábbiak: Read uncommitted (1,2,3) Read committed (2,3) Repeatable read (3) Serializable (egyik fenti probléma sem fordulhat elő) Az Oracle a fentiek közül a Read committed és a Serializable elkülönítési szinteket támogatja, továbbá megmondható egy tranzakcióra, hogy az Read Only legyen. Egy példa a fenti 2. illetve 3. problémára: T1 T2 1- read(X) 2. write(X) 3. commit 4. read(X) Kérdés: T1 ugyanazt látja-e a 4. lépésben, mint az elsőben? Válasz: NEM (feltétlenül) Ennek oka, hogy az adatbáziskezelő alapértelmezés szerint az utasítás szintű READ konzisztenciát garantálja, (ez a fentiek közül a második elkülönítési szint), vagyis, hogy az utasítás végrehajtása közben történt változások láthatatlanok az utasítás számára. Kérdés: Hogyan garantálja az adatbáziskezelő az utasítás szintű READ konzisztenciát? Válasz: A rollback szegmensek segítségével. (Vagy újabb verzióban undo táblatérrel) Mindkettő lényege, hogy a blokknak több példányát (régit és újat) is tárolja a rendszer. A rollback szegmenseket a rendszer véletlenszerűen rendeli a tranzakciókhoz, úgy, hogy nagyjából egyenletes legyen az eloszlás. Az első DML utasítás kiadásakor rendel csak rollback-et a tranzakcióhoz, így aki nem módosít ahhoz nem rendel. (Létezik persze explicit hozzárendelés is -> SET TRANSACTION USE ROLLBACK SEGMENT ...) Az extenseket ciklikus sorrendben allokálja a rendszer, ha az előző már megtelt. Egy extensbe egyszerre több tranzakció is írhat, de minden blokk csak egy tranzakció adatait tartalmazza. Ha a tranzakció commit-ált, akkor az extens felszabadul, de a tartalma még nem törlődik, mert még lehet, hogy szükség lesz rá. Egy lekérdezés elindulásakor a rendszer egy úgynevezett System Change Numbert (SCN) rendel a lekérdezéshez. A módosító utasítások is kapnak ilyet, és az általuk módosított blokkokba is bekerül ez a szám. Így az olvasó utasítás csak azokat a blokkokat olvassa be, amelyeknek az SCN-je régebbi, mint az utasításé. A közben módosult blokkok helyett azok régi verzióját olvassa be a rollback szegmensről. Így persze az is előfordulhat (ha a lekérdezés túl lassú), hogy időközben már a rollback szegmensen sincs meg minden szükséges blokk. Ilyenkor a lekérdezés a következő hibaüzenettel elhal: "ORA-1555: snapshot too old (rollback segment too small)" UNDO táblatér esetén úgy kerülhetjük ezt el, hogy egy init paraméterrel megmondjuk, hogy mennyi ideig őrizze meg a rendszer a régi blokkokat -> UNDO_RETENTION A tranzakció szintű READ konzisztenciát is kérhetjük a rendszertől a megfelelő elkülönítési szint beállításával. (READ ONLY illetve SERIALIZABLE) Ezt a beállítás megtehetjük rendszer, session, vagy tranzakció szinten. READ ONLY csak ez utóbbi szinten állítható be. Csak olvasó tranzakció csak SELECT, LOCK TABLE, SET ROLE, COMMIT, ROLLBACK, ALTER SYSTEM utasításokat adhat ki. SET TRANSACTION ISOLATION LEVEL SERIALIZABLE | READ ONLY| READ COMMITTED ALTER SESSION SET ISOLATION LEVEL SERIALIZABLE | READ COMMITTED ALTER SYSTEM ... Egy szerializálható tranzakció a rendszernek azt az időpontbeli állapotát látja, amikor a tranzakció elindult. (plussz természetesen a saját maga által végzett változtatásokat) Ha közben mások módosítanak és commitálnak azt nem látja. Ha ő is megpróbál olyan adatot módosítani, amit közben egy későbbi tranzakció módosított, (vagyis a szerializálható tranzakció elindulása után történt a commit) akkor a módosító utasítás a következő hibaüzenettel hal el: "ORA-08177: Cannot serialize access for this transaction" Ilyenkor a tranzakció eldöntheti, hogy az eddigi munkáját commit-álja vagy rollback-eli, és esetleg újraindítja önmagát. Vagyis a tranzakció korábbi műveletei azért nem vesztek el!!! Tranzakciók kezelésére szolgáló utasítások: COMMIT, ROLLBACK, SAVEPOINT