Sunteți pe pagina 1din 11

Accesarea bazelor de date Oracle din Perl

Introducere
Perl este un limbaj de programare de nivel nalt orientat spre prelucrarea i
formatarea textelor. Se remarc n primul rnd prin uurina de dezvoltare a aplicaiilor
(mai ales a celor care prelucreaz text) dispunnd de funcii puternice de prelucrare
precum recunoaterea de expresii regulate, indeci asociativi etc. n plus, Perl dispune
de module care realizeaz o multitudine de funcii, de la operaii cu stive, cozi, pn la
sortare, generare automat de grafice, operaii cu socket-uri TCP/IP i acces la baze de
date. Este un limbaj interpretat care se aseamn cu shell-ul UNIX, combinnd n el i
funcii ale altor utilitare UNIX precum sed, cut, awk. Limbajul Perl le extinde ns i le
combin cu puterea expresiilor i operatorilor C, precum i cu faciliti puternice de
programare orientat pe obiecte. Dei este un limbaj interpretat, prin folosirea
funciilor sale foarte puternice se pot obine programe destul de rapide pentru nevoile
obinuite.
Perl are o utilizare foarte larg n dezvoltarea aplicaiilor web, fiind potrivit i
folosit pentru creerea paginilor dinamice (CGI-uri), att n medii de tip Unix (este o
component standard n distribuiile de Linux) ct i n medii Windows. Datorit
funciilor sale care le nglobeaz pe cele oferite de shell-ul Unix, Perl este folosit si in
aplicatiile de administrare ale sistemului de operare Linux.
De cele mai multe ori o aplicaie web dinamic folosete o baz de date, de
unde extrage la cerere anumite date, le formateaz i le afieaz ca o pagin web. Alte
pagini au formulare de culegere de informaii (informaiile respective urmnd s fie
stocate tot ntr-o baz de date). Prin modulul su de accesare a bazelor de date (DBI)
Perl devine o alegere foarte nimerit pentru astfel de aplicaii, avnd avantajul
simplitii n dezvoltare i al portabilitii. Operaiile cele mai complexe (cutri n
baza de date) sunt executate de SGBD, Perl avnd avantajul unui timp de dezvoltare
mai redus decat in cazul unor limbaje de programare compilate, poate putin mai rapide.
Interogarea bazelor de date din Perl
Limbajul Perl poate asigura interogarea unui numr mare de tipuri de baze de
date, de la simplul MsAcces (sau orice alt ODBC) i MySQL pn la Sybase i Oracle.
Fiecare baz de date este diferit. Unele baze de date sunt accesate prin reea,
peste un protocol ca TCP/IP sau IPX, altele sunt accesate local, prin fiiere. Majoritatea
bazelor de date noi sunt accesibile prin reea, prin TCP/IP. De obicei cnd se

achiziioneaz o baz de date, ea vine cu o bibliotec de funcii prin care se poate


accesa baza de date printr-un anumit limbaj, cum ar fi C. Utilizatorul poate astfel s
scrie un program C care s acceseze acea baz de date. Fiecare bibliotec de funcii
este specific fiecrui tip de baz de date, numele funciilor i modul lor de funcionare
variind de la o baz de date la alta. Unele baze de date conin funcii care necesit
includerea datelor de intrare n structuri de date speciale, altele precum Oracle
comunic direct prin interogri SQL trimise prin reea, care sunt prelucrate iar
rezultatul este trimis clientului care a fcut interogarea ntr-un anumit format etc.
Modulul DBI (Database Interface) al limbajului Perl a fost proiectat pentru a
ascunde utilizatorului detaliile de interfaare cu diferitele baze de date. DBI execut
interogarea bazei de date, selectnd n funcie de baza de date folosit un anumit modul
care conine biblioteci de funcii ale productorului, efectund conectarea la baza de
date i predarea rezultatelor ntr-un format standard.Cnd utilizatorul folosete modulul
DBI pentru a accesa o baz de date, el i pred acestuia interogarea, precum i alte
cteva informaii necesare conectrii (username, password), iar acesta l paseaz
modulului DBD (Database Driver) potrivit. Cnd acesta obine rezultatele, le trimite
modulului DBI, care le trimite la rndul lui utilizatorului. Acesta nu trebuie s tie
dect s comunice cu modulul DBI, detaliile de comunicare rmnnd transparente
pentru el. S presupunem c avem dou baze de date, una fiind o baza de date Oracle,
iar cealalt o baz de date Sybase. Lucrnd cu modulul DBI se vor putea accesa
ambele baze de date cu aceleai interogri, modulul Perl realiznd conversiile necesare
pentru a se realiza adaptarea cererii la specificul bazei de date respective. n plus,
bazele de date se pot schimba n mod transparent, fr a fi nevoie de rescrierea codului.
Utilizarea modulului DBI pentru accesarea bazelor de date tip Oracle
Problema 1 (executarea unei interogari simple)
Se d un tabel care conine cmpurile Prenume,Nume,ID_persoana.
Sa se construiasc un program Perl care s caute n baza de date persoanele care au un
anumit nume, afindu-l alturi de ID-ul lor. Numele este citit de la tastatur.
Exemplu:
Introducetinumele:Popescu
118:IonPopescu
Introducetinumele:Ionescu
3:GheorgheIonescu
28:FlorinIonescu
Introducetinumele:Protopopescu
NuafostgasitaniciopersoanacunumeleProtopopescu
Introducetinumele:^D

Programul Perl care rezolv aceast problem este urmtorul:


#!/bin/perl
useDBI;
my$dbh=DBI>connect('DBI:Oracle:personal')

ordie"Numampututconectalabazadedate:".DBI>errstr;
my$sth=$dbh>prepare('
SELECT*
FROMangajati
WHERElastname=?
')
ordie"Nuampututparsaqueryul:".$dbh>errstr;
my@data;
print"Introducetinumele:";
while($lastname=<>){#Citescinputulutilizatorului
chomp$lastname;
$sth>execute($lastname)#Executaqueryul
ordie"Nupotexecutaqueryul:".$sth>errstr;
#Citescinregistrarilecareaufacutmatchsileafisez
while(@data=$sth>fetchrow_array()){
my$firstname=$data[1];
my$id=$data[2];
print"\t$id:$firstname$lastname\n";
}
if($sth>rows==0){
print " Nu a fost gasita nici o persoana cu numele
`$lastname'.\n\n";
}
$sth>finish;
print"\n";
print"Introducetinumele:";
}
$dbh>disconnect;

Explicaii asupra programului


Prima linie este specific sistemelor de operare de tip UNIX (de exemplu
Linux) i instruiete sistemul s apeleze interpretorul Perl pentru a executa programul.
Continand aceasta linie, pe sistemul de operare Linux programul se va putea executa
doar tastatndu-i numele. In lipsa acestei linii ar trebui apelat explicit interpretorul
Perl. Pe sistemele non.UNIX aceasta linie este ignorata, caracterul # la inceputul unei
linii semnificnd n Perl c acea linie este un comentariu, i deci nu este luat n
considerare de interpretor.

Pentru accesarea din Perl a unei baze de date trebuie n primul rnd ncrcat
modulul DBI. Aceast directiv este comunicat interpretorului Perl prin linia:
useDBI;

Urmtorul pas foarte important este conectarea la baza de date. Pentru aceasta
se folosete metoda connect a obiectului DBI. Aceasta este o funcie care realizeaz
conectarea la baza de date. Orice aplicaie Perl care interogheaz o baz de date trebuie
s conin un astfel de apel.
my$dbh=DBI>connect('DBI:Oracle:personal')
ordie"Numampututconectalabazadedate:".DBI>errstr;

Se observ specificarea tipului bazei de date (Oracle) i a numelui bazei de


date. n cazul n care se face portarea programului pe o baz de date Sybase de
exemplu, se va nlocui Oracle cu Sybase. Dac accesul la baza de date presupune
autentificare cu username i password sau trebuie specificat IP-ul calculatorului pe
care se afl baza de date, acestea se vor trimite ca argumente tot metodei connect:
my$dbh=DBI>connect('DBI:Oracle:personal;hostname=
193.231.236.54',username,password)
ordie"Numampututconectalabazadedate:".DBI>errstr;

Se observ aici c metoda connect are numr variabil de argumente i c


dup apelul funciei se poate obine textul asociat codului de eroare prin DBI
>errsr. n acest exemplu textul asociat codului de eroare este afiat folosind funcia
die, functie care apeleaz automat funcia exit pentru terminarea anormal a
programului. Se folosete un artificiu prin legarea celor dou funcii cu operatorul
logic or, astfel nct dac prima funcie returneaz true atunci nu se mai evalueaz a
doua funcie (deci nu se face afiarea codului de eroare i ieirea din program). Se
folosete operatorul . pentru concatenarea textului explicativ introdus de utilizator
cu textul de eroare returnat de functie.
Pentru compilarea interogrii se folosete metoda prepare. Compilarea
nseamn pentru unele baze de date de nivel nalt (cum este Oracle) apelarea serverului
bazei de date pentru traducerea n limbajul intern propriu. Dac prepare are succes,
va returna un handler de stare al interogrii. n cazul n care eueaz, returneaz un
mesaj de eroare n $dbh>errstr.
Urmeaz o simpl afiare de mesaj pentru utilizator. Se putea folosi i funcia
printf cu sintaxa obinuit din C, dar aceast scriere este mai scurt i mai puin
criptic.

print"Introducetinumele:";

Este necesar apoi un ciclu while pentru a se cere n mod repetat utilizatorului
s introduc un nume spre cutare. Urmatoarea secven realizeaz citirea de la
terminal a unei linii. Simbolul format din caracterele <si> alaturate reprezint
linia curent din buffer-ul de citire de la terminal. n cazul n care citirea eueaz, bucla
while se termin.
while($lastname=<>){

Trebuie apoi compilat interogarea intr-un format intern al bazei de date.


Compilarea se face doar o singur dat, chiar dac execuia se face de mai multe ori,
deci metoda prepare va trebui plasata in afara buclei while.
my$sth=$dbh>prepare('
SELECT*
FROMangajati
WHERElastname=?
')

Datele intermediare se vor reine n variabila data. Caracterul @ din fata


semnifica faptul ca este o variabila lista de elemente, in cazul nostru va fi o list de
iruri . In Perl varibilele nu trebuiesc delarate explicit, se initializeaz la prima folosire.
Pentru a face ns ca o variabil sa fie local functiei trebuie totui s se realizeze un
fel de declarare, prefixnd numele ei cu un cuvant cheie :my
my@data;

In interiorul buclei while se face prima dat eliminarea caracterului de sfrit


de linie din linia citit.Prima citire se executa n exteriorul buclei while, celelalte se
execut n finalul buclei.
chomp$lastname;

Pentru execuia interogrii pe care a pregtit-o cu funcia prepare se


foloseste metoda execute. Tratarea eecului execuiei se va face similar cu cea de la
apelurile anterioare.
$sth>execute($lastname)

ordie"Nupotexecutaqueryul:".$sth>errstr;

Funcia fetchrow_array ntoarce o linie din tabelul rspuns,


incrementnd cursorul la urmtoarea linie. n cazul n care s-a ajuns dup ultima linie,
metoda ntoarce o list vid de coloane, caz n care se iese din bucla while.
while(@data=$sth>fetchrow_array()){

Se vor extrage n dou variabile informaiile din coloanele 1 si 2. Pentru o mai


mare flexibilitate s-ar fi putut face SELECT, specificnd exact coloanele de care este
nevoie, dar n exemplul nostru vom presupune c se cunoate ordinea coloanelor
(Prenume, Nume, ID,). In Perl indexarea listelor ncepnd de la 0, deci $data[0]
ar reprezenta numele, $data[1]reprezint prenumele, iar $data[2]reprezint.
ID-ul.
my$firstname=$data[1];

my$id=$data[2];

Se va afia apoi linia rezultat, cu un tab n fa. Se observ c variabilele se pot


insera direct n siruri dac nu este nevoie de o formatare special.
print"\t$id:$firstname$lastname\n";

Se va afia un text de eroare dac nu a fost gsit nici o nregistrare cu acel


prenume. Metoda rows ntoarce numrul de coloane din nregistrare, iar n cazul n
care nu mai exist nici o nregistrare ntoarce 0.
if($sth>rows==0){
print " Nu a fost gasita nici o persoana cu numele
`$lastname'.\n\n";
}
$sth>finish;
print"\n";

n final trebuie instruit modulul DBI s informeze baza de date c toate datele
au fost citite i se pot elibera resursele alocate. n cazul n care se face o singur
interogare se poate sri peste acest pas, resursele dealocndu-se la sfritul
programului. Este totui recomandabil s se foloseasc metoda finish, pentru o

gestionare eficient a memoriei pn la sfritul programului, sfrit care poate ntrzia


mult dup terminarea accesului la baza de date.
Metoda finish informeaz doar baza de date c datele au fost citite n
ntregime. Se va folosi disconnectpentru deconectarea de la baza de date, aceasta
nsemnnd de exemplu nchiderea conexiunii TCP/IP care a fost activ, chiar dac nu
s-au mai fcut accesri la baza de date.
$dbh>disconnect;

Acesta a fost doar un exemplu didactic. Cu interogri mai complicate i


prelucrri ulterioare se pot realiza foarte uor operaiuni foarte complicate n alte
limbaje de programare. Prezentul exemplul poate rula cu minime modificri pe
aproape orice baz de date, dar interfaa DBI nu se oprete la att. Ea poate folosi
eficient facilitile avansate ale bazelor de date profesioniste, cum ar fi tranzacii sau
optimizri ale accesului la baza de date prin pstrarea n cache a interogrilor
compilate deja.
Problema 2 (Utilizarea facilitii cached queries)
Se d un tabel people care conine cmpurile ID i age. S se construiasc o funcie
Perl care primete ca argument ID-ul unei persoane i care returneaz varsta acesteia.
Se presupune c s-a realizat deja conectarea la baza de date.
O functie care realizeaz acesta este urmatoarea:
subage_by_id{
#Argumente:handlerulbazeidedate,IDulpersoanei
my($dbh,$id)=@_;
my$sth=$dbh>prepare(
SELECTage
FROMpeople
WHEREid=?
)
ordieNumapotconectalabazadedate:.$sth>errstr;
$sth>execute($id)
ordieNupotexecutaqueryul:.$sth>errstr;
my($age)=$sth>fetchrow_array();
return$age;
}

Functia pregtete interogarea, o execut i ntoarce rezultatul. Se observ c


argumentele funciei nu sunt definite explicit. In Perl se pot extrage argumentele unui
functii ca o list de argumente. Aceast list este desemnat prin @_. In exemplu de
fat s-au extras primele dou elemente ale listei. S-ar putea efectua i alte verificri ale
tipurilor argumentelor, dar n cazul de fa se presupune c argumentele sunt trimise
corect. Variabilele n Perl nu trebuie declarate explicit, dar pentru a prentmpina
suprapunerea numelor variabilelor cu unele definite n program se prefixeaza prima
folosire a variabilei cu my care face ca aceste variabile s fie locale funciei.
Dac funcia este apelat de un numr mare de ori, metoda prepare se
execut la fiecare apel, dei ea pregtete pentru execuie aceeai interogare. Dup cum
se observ, ID-ul este pasat la execuie, nefcnd parte din interogarea care se
compileaz. O variant mai elegant este folosirea facilitii native cached query,
prin folosirea metodei prepare_cached n locul metodei prepare. n acest caz se
va recompila interogarea doar dac aceasta s-a modificat de la apelul anterior, deci se
vor economisi resurse ale sistemului in cazul n care se execut apleluri repetate ale
funciei.
subage_by_id{
#Argumente:handlerulbazeidedate,IDulpersoanei
my($dbh,$id)=@_;
my$sth=$dbh>prepare_cached(
SELECTage
FROMpeople
WHEREid=?
)
ordieNumapotconectalabazadedate:.$sth>errstr;
$sth>execute($id)
ordieNupotexecutaqueryul:.$sth>errstr;
my($age)=$sth>fetchrow_array();
return$age;
}

Problema 3 (modificri atomice tranzacii)


Se da o baz de date care conine dou tabele: employees (angajai) i
departments (departamente). Tabelul employees conine cmpurile
FIRSTNAME, LASTNAME, DEPARTAMENT_ID, iar departments
conine ID, NAME, NUM_MEMBERS. Problema care apare la adugarea unui
angajat este c exist posibilitatea ca, dup adugarea angajatului, interogarea de
incrementare a numrului de angajai din departamentul respectiv s eueze, rezultnd
o inconsisten n baza de date. n plus, o accesare concurent face posibil ca un alt
program s acceseze baza de date ntre cele dou interogri, folosind deci o baz de

date inconsistent. Sa se realizeze o functie Perl care sa realizeze introducerea unui nou
angajat in baza de date in mod atomic sa nu poata apare situatia prezentata mai sus.
Bazele de date avansate (precum Oracle) suport aa-numitele tranzacii,
adic modificri atomice ale bazei de date (care ori se realizeaz n ntregime, ori nu se
realizeaz deloc). De multe ori acest lucru este foarte necesar, modificri ale bazei de
date ntrerupte de evenimente neprevzute (cum ar fi ntreruperi ale alimentrii cu
energie electric sau blocaje ale sistemului de operare) putnd duce la inconsistene ale
bazei de date, greu de descoperit i eliminat. Soluia este ca aceste modificri critice
s se efectueze ntr-o zon separat de baza de date, urmnd ca la apelul unei funcii
commit s fie efectuate modificrile n mod atomic. Detaliile de implementare a
tranzaciilor sunt specifice fiecrei baze de date, eventual algoritmi nepublici.
Iat un exemplu de folosire a tranzaciilor, n care se valideaza modificarile
apelndu-se funcia commit n cazul n care ambele interogri se termin cu succes
sau anulndu-se modificrile facute prin functia rollback n cazul n care una dintre
ele nu se execut cu succes. De notat faptul ca n cazul n care nu se execut funcii
specifice tranzaciilor, Perl apeleaz automat la sfritul programului commit. nainte
de execuia programului este ns posibil s se apeleze rollback pentru anularea
modificrilor fcute.
subnew_employees{
#Argumente:handlerulbazeidedate,numelesiprenumele
#angajatului,IDuldepartamentului
my($dbh,$first,$last,$department)=@_;
my($insert_handle,$update_handle);
my$insert_handle=
$dbh>prepare_cached(
INSERT
INTOemployees
VALUES(?,?,?)
);
my$update_handle=
$dbh>prepare_cached(
UPDATEdepartments
SETnum_members=num_members+1
WHEREid=?
);
dieNupotpregatiqueryurilepentruexecutie
unlessdefined$insert_handle&&defined$update_handle;
my$success=1;
$success&&=$insert_handle>execute($first,$last,$department);
success&&=$update_handle>execute($department);
my$result=($success?$dbh>commit:$dbh>rollback);

unless($result){
dieNupotfinalizatranzactia.$dbh0>errstr
}
return$success;
}

Exemplul este destul de simplu de neles, impunndu-se doar cteva precizri


asupra unor sintaxe nou aprute. Se observ notaia prescurtat folosind operatorul
unless, foarte aproape de limbajul natural, care execut blocul de comenzi dac nu sa realizat condiia. n plus mai apare operatorul ?, similar cu cel din C, care returneaz
n funcie de primul argument pe unul dintre urmtoarele dou. Mai este folosit
operatorul &&=, tot cu semnificaia din C adic se face and logic ntre valoarea din
stnga i valoarea din dreapta operatorului, iar rezultatul este stocat n variabila din
stnga. Variabila $success este initializata cu 1, deci dup cele dou execuii de
interogri va avea ca valoare and-ul logic ntre valoarile ntoarse de cele dou apeluri.
i cu alte baze de date se pot folosi tranzaciile n mod similar.
Observatii:
Atunci cnd se fac interogri care nu trebuie executate atomic, sunt
necesare foarte multe commit-uri. Pentru a elimina aceast necesitate se
poate folosi opiunea AutoCommit la apelul functiei de conectare la baya
de date. In acest caz se va face commit dup fiecare interogare executat
corect:
my$dbh=DBI>connect(DBI:Oracle:personal,{AutoCommit=>1},)
ordieNumapotconectalabazadedatecuAutoCommit.DBI
>errstr

Dac n cazul apariiei unei erori ceea ce se dorete este ieirea din
program, se poate instrui modulul DBI s fac asta automat, cu un apel de
genul:

my$dbh=DBI>connect(DBI:Oracle:personal,{RaiseError=>1},)
ordieNumapotconectalabazadedatecuRaiseError.DBI
>errstr

ncheiere
Acestea au fost numai cteva exemple de construire a programelor de accesare
a bazelor de date Oracle din Perl. Combinndu-le se pot creea uor programe foarte

puternice, care s beneficieze de puterea bazei de date Oracle i de simplitatea de


scriere a limbajului Perl. Exist i alte opiuni posibile, unele scurtturi, optimizri, dar
lsm cititorului plcerea de a le descoperi i a le studia pe msur ce avanseaz n
cunoaterea acestui limbaj.

S-ar putea să vă placă și