A PL/SQL blokk a következő utasításokat tartalmazhatja:
A trigger egy olyan tevékenység, amelyet bizonyos, az adatbázis használatakor bekövetkező, események alkalmával kell végrehajtani. A triggereket a deklaratív hivatkozási integritás kiterjesztésére, komplex üzleti szabályok kezelésére, az adatok változásának követésére lehet használni. A tevékenységet leíró kód, a trigger törzse nem más, mint egy PL/SQL blokk. A triggerek működése a felhasználó számára átlátszó módon történik. A trigger lefutása
automatikusan bekövetkezik, ha az adatbázis bizonyos tábláin egy insert, delete vagy update utasítás végrehajtódik. Ahhoz hogy egy táblán triggert hozhassunk létre, meg kell tudnunk változtatni a táblát. Ehhez vagy a tábla tulajdonosának kell lennünk vagy rendelkeznünk kell a táblára vonatkozó ALTER privilégiumokkal vagy az ALTER ANY TABLE rendszerprivilégiumokkal. A triggert SQL utasítással hozhatjuk létre (CREATE TRIGGER), de a trigger végrehajtható részét PL/SQL nyelven kell megírnunk. A triggerhez tartozik egy kiváltó (elsütő) művelet (INSERT, DELETE, UPDATE). A trigger egy objektumhoz (tábla vagy esetleg nézet) kötődik.
A trigger egy módosító művelet előtt vagy után fut le.
Trigger típusa:
Ha megadjuk a FOR EACH ROW opciót akkor a trigger minden sorra egyszer végrehajtódik. Az ilyen triggereket sor-triggernek hívjuk.
Ellenkező esetben csak utasításonként egyszer hajtódik végre a trigger. Ekkor a neve utasítás-trigger.
When feltétel csak sortriggerre adható meg. Ilyenkor a trigger csak azokra a sorokra fut le, amelyek kielégítik a feltételt. Triggerek engedélyezhetők vagy letilthatók (ALTER TRIGGER) Ha egy művelet több triggert is aktivizál akkor azok futási sorrendje nem garantált. Triggeren belül nem adható ki tranzakciókezelő utasítás. COMMIT, ROLLBACK, SAVEPOINT Az oszlopok régi és új értékére a PL/SQL blokkban úgy hivatkozhatunk mint host változókra. (kettőspont a változó előtt: :NEW.oszlop, :OLD.oszlop) BEFORE triggerben az új értéket meg is változtathatjuk és ekkor ez kerül be majd az oszlopba. AFTER trigger esetén ezt nem tehetjük meg. Egy AFTER trigger viszont már használhatja a ROWID-jét a sornak.
14 féle trigger létezik. A trigger fajtáit az adatbázis-műveletet, a trigger művelethez viszonyított végrehajtási ideje és a szint dönti el,amelyen a trigger végrehajtódik.
Végrehajtás ideje | Művelet | Szint |
BEFORE | INSERT | sor |
BEFORE | INSERT | utasítás |
AFTER | INSERT | sor |
AFTER | INSERT | utasítás |
BEFORE | UPDATE | sor |
BEFORE | UPDATE | utasítás |
AFTER | UPDATE | sor |
AFTER | UPDATE | utasítás |
BEFORE | DELETE | sor |
BEFORE | DELETE | utasítás |
AFTER | DELETE | sor |
AFTER | DELETE | utasítás |
INSTEAD OF | - | sor |
INSTEAD OF | - | utasítás |
A sorszintű triggerek egy tranzakción belül minden egyes sorra pontosan egyszer hajtódnak végre. Létrehozásuk a CREATE TROGGER parancs FOR EACH ROW utasításrészének megadásával történik.
Az utasításszintű triggerek minden tranzakcióra csak egyszer hajtódnak végre, függetlenül attól hogy hány sort dolgoznak fel. Ezeket a triggereket általában csak akkor használjuk, ha ha egy adott táblát feldolgozó teljes tranzakcióhoz akarunk valamilyen kiegészítést rendelni.
Mivel a triggerek eseményekhez kapcsolódnak, lehetséges, hogy közvetlenül az adott esemény előtt vagy után fussanak le. Ha például egy beszúrandó sor egy oszlopát a triggerben akarjuk beállítani ,akkor BEFORE INSERT triggert kell alkalmaznunk, hogy elérje az új értéket. Egy AFTER INSERT trigger esetén a beszúrt értéket már nem tudjuk beállítani.
Olyan műveletek, melyek azon műveletek helyett futnak le, amelyek aktivizálták őket. Például ilyen triggerekkel tudunk egy beszúrást átirányítani egy másik táblába, vagy egy adott nézethez tartozó több táblán ezzel tudjuk végrehajtani a módosítást.
A következő triggert egy nézetre hívtuk meg, amely az összfizetéseket tartalmazza egy osztályra nézve. Ha az osztály neve (DNAME) változik, akkor a trigger megváltoztatja ezt a a DEPT táblában, ha pedig az összfizetés (SUMSAL) változik, akkor az adott osztály összes dolgozójának fizetése egyforma mértékben változik meg, úgy, hogy a változtatás utáni összfizetés az előre megadott összfizetéssel egyezik meg.
Egy SQL utasítás feldolgozásához az Oracle a memóriában egy
speciális területet használ, melyet környezeti területnek hívunk.
A környezeti terület információkat tartalmaz az utasítás által
feldolgozott sorokról, lekérdezés esetén tartalmazza a visszaadott
sorokat (amit aktív halmaznak nevezünk) és tartalmaz egy mutatót
az utasítás belső reprezentációjára. Ez a mutató a kurzor.
A kurzor olyan eszköz, amellyel megnevezhetjük a környezeti
területet, segítségével hozzáférhetünk az ott elhelyezett
információkhoz és amennyiben az aktív halmaz több sort tartalmaz,
azokat egyenként elérhetjük, feldolgozhatjuk.
A PL/SQL kétfajta kurzort kezel, az explicit és az implicit
kurzort. A PL/SQL automatikusan felépít egy implicit kurzort
minden DML utasításhoz, beleértve az olyan lekérdezéseket is,
amelyek pontosan egy sort adnak vissza. A több sort visszaadó
lekérdezések eredményének soronkénti kezeléséhez viszont
explicit kurzort célszerű használnunk. Megjegyzendő, hogy
az explicit kurzor hatékonysága általában rosszabb, mint az
implicit kurzoré.
Egy explicit kurzor kezelésének négy lépése van, ezek az alábbiak:
Kurzort deklarálni a PL/SQL blokk deklarációs részében tudunk, az alábbi szintaxissal:
Az alábbi példa mutatja be, hogy hogyan használjunk egy kurzort:
Miután deklaráltuk a kurzort a deklarációs blokkban, a blokk
törzsében nyissuk meg a kurzort az OPEN kulcsszó segítségével.
Miután a kurzort megnyitottuk egy ciklussal tudunk végig iterálni
az eredményhalmazon, hogy soronként dolgozhassuk fel azt.
Az éppen aktuális sort a FETCH kulcsszóval tudjuk elkérni egy
olyan változóba, aminek a típusa megegyezik a kurzor eredményhalmazának
a visszatérési értékével (tehát ha nem csak egy oszlopot ad vissza, akkor
rekord kell). Meg kell adnunk egy kilépési feltételt is, ez rendszerint a
kurzor érvénytelen memóriacímre mutatásának vizsgálata használatos, azaz
az EXIT WHEN kurzornév%NOTFOUND utasítás.
A ciklus után amilyen sürgősen csak tudjuk, zárjuk be a kurzort, a
CLOSE kurzornév parancs segítségével, hogy felszabadítsuk a lefoglalt
erőforrásokat.
A kurzorok nagy szolgálatot tesznek minden PL/SQL
programozónak a mindennapokban, mert egyszerű és kényelmes
használni őket, és nagyfokú sokoldalúságot biztosítanak
a munkánk során. Érdemes azonban megismerni a pontos
működésüket, mert ha úgy használunk egy kurzort, hogy
nem ismerjük a korlátait, vagy esetleg (a kényelem miatt)
nem törödünk azokkal, akkor a kódunk optimalizálatlan
és lassú is lehet.
A kurzor valójában nem egy lekérdezés, sem egy tároló, hanem
egy pointer, ami egy lekérdezés eredményhalmazának egy sorára
mutat. Amikor megnyitunk egy kurzort az eljárásunkban, és
lekérjük az eredményének a következő sorát a FETCH utasítással,
akkor minden kurzor sor lekérdezés külön-külön küldődik el a
kliensünktől a szervernek, hogy az parse-olja, lekérdezéstervet
generáljon, végrehajtsa, az eredményhalmazt pedig visszaküldje a
kliensnek. Mivel a PL/SQL eljárásunk PL/SQL kódot küld a szervernek,
amit annak át kell alakítania SQL kóddá, majd ugyanezt visszafelé is,
ezért rengeteg PL/SQL - SQL kontextusváltáson is keresztül megy
a kódunk, ami nagyon sokat lassít a program hatékonyságán.
Ez a probléma főleg a régebbi Oracle verzióknál érezhető nagyon,
10g verzión például ez egy nem elhanyagolható dolog, amire igenis
oda kell figyelnünk. Fontos kiemelni továbbá, hogy ahhoz, hogy az
Oracle el tudja tárolni átmenetileg a lekérdezésünk eredményhalmazát,
ahhoz több fajta erőforrást igénybe kell vennie, például zárakat,
memóriát, akár még lemezterületet is. Ezért, ha nem akarjuk, hogy
ez a sok erőforrás fölöslegesen maradjon lefoglalva hosszú ideig,
akkor minnél hamarabb zárjuk be a kurzorunkat, minnél hamarabb
bezárjuk a kurzort, annál jobb.
Nyitva tartani egy kurzort olyan, mint nyitva tartani a hűtőt.
Ok nélkül nem tesszük órákig, de ez nem jelenti azt, hogy sohasem
kell kinyitnunk a hűtőt.
A kurzor arra való, hogy egy lekérdezés eredményhalmazát sorról
sorra tudjuk feldolgozni.
Ez azt jelenti, hogy:
A triggerek nagyon sok munkát megspórolhatnak nekünk, és a használatuk
kényelmes. Érdemes azonban épp úgy odafigyelni használatukra, mint
a kurzoroknál, mert ha elárasztjuk az adatbázis triggerekkel, akkor
nagyon komoly teljesítmény problémákkal kellhet majd szembenéznünk.
Oracle-ben a DML utasításokhoz rendelt FOR EACH ROW triggerek
valójában kurzorok, így igaz rájuk a kurzorok minden hátulütője is.
Egy FOR EACH ROW trigger puszta létezése is lelassíthatja a DML utasítások
futásának az idejét tizedére is akár.
Az alábbi script Oracle 10g verzióban lett futtatva.
Látható, hogy beszúrtunk 1.000.000 sort egy táblába, ami másfél másodperc alatt lefutott. Ez után létrehoztunk egy üres triggert (olyan triggert, ami nem csinál semmit), majd megint beszúrtunk 1.000.000 sort a táblába, ami viszont a trigger miatt már 17 és fél másodpercig tartott, pedig a trigger még csak nem is végzett semmilyen műveletet. Ezt a lassulási lehetőséget minden képpen tartsuk szem előtt, ha triggert akarunk létrehozni az adatbázis egy táblájához!
Egy PL/SQL program szövegébe csak DML és tranzakcióvezérlő utasítások építhetők be, DDL utasítások nem. Bárhol használhatók, ahol végrehajtható utasítások állhatnak. Minden SQL utasítás alkalmazásához a PL/SQL a natív dinamikus SQL eszközét használja.
A PL/SQL-ben a SELECT, DELETE, INSERT, UPDATE, MERGE utasítások speciális változatai használhatók.
SELECT INTO
A SELECT INTO utasítás egy vagy több adatbázistáblát kérdez le és a származtatott értéket változokba vagy egy rekordba helyezi el. Alakja:
DELETE
A DELETE utasítás egy adott tábla vagy nézet sorait törli. Alakja:
INSERT
Az INSERT utasítás új sorokkal bővít egy megadott táblát vagy nézetet. Alakja:
UPDATE
Az UPDATE utasítás megváltoztatja egy megadott tábla vagy nézet adott oszlopainak értékét. Alakja:
MERGE
A MERGE utasítás a többszörös INSERT és DELETE utasítások elkerülésére való. Alakja:
Az Oracle működése közben munkameneteket kezel. Egy felhasználói munkamenet egy alkalmazás vagy egy Oracle-eszköz elindításával, az Oracle-hez való kapcsolódással indul. A munkamenetek egyidejűleg, párhuzamosan, az erőforrásokat megosztva működnek. Az adatintegritás
megőrzéséhez az Oracle konkurenciavezérlést alkalmaz.
A konkurens adatok elérését zárakkal biztosítja az Oracle. Ez a zár átmenetileg tulajdonosi jogkört biztosít a felhasználó számára egy táblára, vagy egy tábla bizonyos soraira. Amíg a zárolás fennáll, addig más felhasználó nem hajtat végre módosítást az adatokon.
A tranzakció nem más, mint DML-utasítások sorozata, amelyek a munka egyik logikai egységét alkotják. Utasításainak hatása együtt jelentkezik. Sikeres végrehajtás esetén a módosítások véglegesítődnek. Ha valamilyen hiba folytán a tranzakció sikertelen, akkor
visszagörgetődik, és az adatbázis állapota nem változik meg. Lehetőség van részleges visszagörgetésre is.
A tranzakció explicit végegesítésére a COMMIT utasítás szolgál. Alakja:
A WORK csak az olvashatóságot szolgálja.
A COMMIT a tranzakció által okozott módosításokat átvezeti az adatbázisba és láthatóvá teszi más munkamenetek számára, felold minden zárat, és törli a mentési pontokat.
A SAVEPOINT utasítással egy tranzakcióban mentési pontokat helyezhetünk el. Ezek a tranzakció részleges visszagörgetését szolgálják. Alakja:
A visszagörgetést a ROLLBACK utasítás végzi, alakja:
Az egyszerű ROLLBACK utasítás érvényteleníti a teljes tranzakció hatását, oldja a zárakat és törli a mentési pontokat, és a tranzakció befejeződik.
Az Oracle minden INSERT, UPDATE, DELETE utasítás elé elhelyez egy implicit mentési pontot. Ha az utasítás sikertelen, akkor az Oracle automatikusan visszagörgeti.
Fontos, hogy egy PL/SQL blokk és a tranzakció nem azonosak. A blokk kezdete nem indít el tranzakciót, és a záró END sem jelenti a tranzakció végét.
A tranzakció tulajdonságai
Egy tranzakció tulajdonságait a SET TRANSACTION utsítással állíthatjuk be. Mindig a tranzakció az első utasításának kell lennie. Alakja:
A READ ONLY csak olvasható tranzakciót indít el. Egy csak olvasható tranzakcióban SELECT INTO (FOR UPDATE nélkül), OPEN, FETCH, CLOSE, LOCK TABLE, COMMIT és ROLLBACK utasítások helyezhetők el.
A READ WRITE az aktuális tranzakciót olvasható-írható tranzakcióvá nyilvánítja. A tranzakcióban minden DML-utasítás használható.
Az ISOLATION LEVEL az adatbázist módosító tranzakciók kezelését adja meg. A READ COMMITTED az alapértelmezett, ennél szigorúbb szintet a SERIALIZABLE explicit megadásával írhatunk elő.
A NAME által a tranzakcióhoz hozzárendelt sztring hozzáférhető a tranzakció futása alatt, lehetővé teszi a monitorozást, vagy elosztott tranzakciók kezelését.
Explicit zárolás
Az Oracle automatikusan zárolja az adatokat, azonban a felhasználó is zárolhat explicit módon egy táblát vagy egy tábla bizonyos sorait.
A SELECT FOR UPDATE utasítással a kérdés által leválogatott sorok egy későbbi utasítás számára lefoglalásra kerülnek. Ezt akkor érdemes használni, ha biztosak akarunk lenni abban, hogy az adott sorokat nem módosítja más felhasználó a mi módosításunk előtt.
Ha olyan UPDATE vagy DELETE utasítást használunk, amelyikben szerepel CURRENT OF utasításrész, akkor a kurzorban kötelező a FOR UPDATE utasítás.
A LOCK TABLE segítségével egy vagy több táblát tudunk zárolni. Alakja:
A mód lehet: ROW SHARE, ROW EXCLUSIVE, SHARE, SHARE UPDATE, SHARE ROW EXCLUSIVE, EXCLUSIVE.
Autonóm tranzakciók
Egy tranzakció elindíthat egy másik tranzakciót. Gyakori, hogy ezek az elindított tranzakciók az indított tranzakciótól teljesen elkülönülten működnek, az ilyen tranzakciók autonómok. Az autonóm tranzakció független, nincs megosztott zár, erőforrás a fő tranzakcióval.
Előnye, hogy az újrafelhasználást segítő szoftverkomponensek állíthatók elő.
Létrehozására egy pragma szolgál, elhelyezhető egy rutin deklarációs részében. Alakja:
Felhasználó által definiált zárak
Felhasználói zárak létrehozására a DBMS_LOCK csomag ad lehetőséget. Lefoglalhatunk egy új zárat megadott zárolási móddal, elnevezhetjük azt, hogy más munkamenetben is látható legyen, megváltoztatjuk a zárolás módját, és végül feloldhatjuk.
Segítségükkel kizárólagos hozzáférést biztosíthatunk egy adott eszközhöz, létrehozhatunk alkalmazás szintű olvasási zárat, érzékelhetjük egy zár feloldását vagy szinkronizációs eszközként kikényszeríthetjük az alkalmazások szekvenciális végrehajtását.