Documente Academic
Documente Profesional
Documente Cultură
Programare SQLJ
Cnd dorim s scriem un program care acceseaz o baz de date dintr-un program Java, ntrebarea este: Ce vom folosi, JDBC sau S !J"
Monica Cioat
n ultimii ani, Java a devenit limbajul preferat al dezvoltatorilor de aplicaii Internet/Intranet. Apleturile i servleturile Java apar peste tot pe Web, oferind o bogat funcionalitate unui mediu, p!n nu demult, eminamente static. "iturile Web au devenit veritabile furnizoare i colectoare de informaii, iar de cele mai multe ori aceste informaii trec printr#o baz de date. $eci accesarea unei baze de date este o problem care trebuie rezolvat de fiecare dat c!nd dorim s construim astfel de aplicaii. $ac ai mai accesat din Java baze de date, vei spune J$%& este soluia i nu v pot contrazice' dar pot spune c soluia J$%& poate fi acum ameliorat graie noii te(nologii ")*J menit s simplifice acolo unde e posibil modul de acces la baza de date.
Un exemplu
")*J este o cale standard de includere a comenzilor ")* statice direct +n programe Java. ,oua te(nologie este rezultatul unei colabor ri -racle, I%., "/base, 0andem i Informi1, dup modelul standardului A,"I/I"- de legare a comenzilor ")* +n programe &, &-%-*, 2-303A, sau alte limbaje. -racle implementase anterior 4ro5& un produs ce permite utilizarea comenzilor ")* +n programe &. &u alte cuvinte, ")*J ar fi un soi de 4ro5Java. $eoarece #ro$an%t&ing desemneaz o te(nologie 6specific 7/ proprietar -racle, iar ")*J este un standard desc(is, nu s#a ales denumirea de 4ro5Java. $up cum vom vedea +n acest articol, dei ")*J simplific scrierea, gestiunea i depanarea aplicaiilor Java, el nu +nlocuiete J$%&. $in contr , implementarea -racle pentru ")*J c(iar folosete J$%&. 4entru a +nelege cum funcioneaz ")*J s lu m urm torul e1emplu8 presupunem c avem o tabel , emp, +n baza de date care conine informaii despre angajaii unei firme, iar printre c!mpurile acesteia8 ename # numele i sal # salariul angajatului. $orim s afi m numele tuturor angajailor care au salariul mai mare dec!t o valoare dat . &odul J$%& +n acest caz ar putea fi8 // 64resupunem c avem deja un obiect J$%& &onnection conn7 // definim variabile Java "tring name' int id9:;<<=' float salar/9>????' // &onstruim un obiect J$%& 4repared"tatement. 4repared"tatement pstmt 9 conn.prepare"tatement 6@select ename from emp A(ere empno9B and salCB@7' pstmt.setInt6<, id7' pstmt.set2loat6>, salar/7' // D1ecutam o interogare' valorile obtinute sunt //asignate unei variabile Java. 3esult"et rs 9 pstmt.e1ecute)uer/67' A(ile 6rs.ne1t677 E name9rs.get"tring6<7' "/stem.out.println6@,umele este8 @ F name7' G rs.close67 pstmt.close67' 4rimele trei linii definesc variabilele Java name, id i salar/. Hrm toarea linie realizeaz un apel de preg tire a unei instruciuni 6prepared statement7. 4resupun!nd c deja este stabilit o cone1iune prin J$%& la baza de date, putem folosi metoda prepare"tatement67 # metod a obiectului conn derivat din clasa &onnection 6cone1iune7. #reparedStatement este folosit atunci c!nd +n interiorul comenzii ")* avem nevoie de un set dinamic de valori, ceea ce +nseamn c o aceeai instruciune gata preg tit 6prepared statement7 poate fi folosit de oric!te ori pentru diferite valori ale variabilelor. Interogarea este format +ntr#o instan 6pstmt7 a clasei 4repared"tatement +n timp valorile variabile sunt p strate +n variabile Java i transmise prin apelurile pstmt.setInt67 i pstmt.set2loat67. 4rimul @B@este +nlocuit cu valoare variabilei id, deci un int a c rui valoare este :;<<=. Al doilea @B@ este +nlocuit cu valoarea variabilei salar/ 6un float a c rui valoare este >????7. Hrmeaz e1ecuia interog rii, datele rezultat fiind returnate +ntr#un obiect 3esult"et al J$%&. n final, datele sunt e1trase din setul rezultat i afiate. Hn set rezultat
conine de obicei mai multe linii de date, dar +n acest e1emplu avem o singur linie. $up cum se poate lesne constata, avem destul de lucru pentru a realiza o simpl interogare. ,e putem imagina atunci comple1itatea apelurilor ")* multilinie +n care avem mai multe variabile Java. Inevitabil dup un timp ne vom pune +ntrebarea @Cum putem face ca din Java interogrile s fie mai u'or de realizat"@ "implificarea procesului de interogare Aa cum b nuii deja r spunsul la +ntrebarea noastr este8 folosind S !J. 4entru a ne da seama de avantajele ")*J s transcriem e1emplul de mai sus folosind ")*J8 "tring name' int id9:;<<=' float salar/9>????' IsJl Eselect ename into 8name from emp A(ere empno98id and salC8salar/7' "/stem.out.println6@,ame is8 @ F name7' &e observ m analiz!nd acest codB 4rimul lucru, un cod mult mai concisK D1plicaiaB ")*J permite comenzilor ")* s fie legate direct +n codul Java i accept ca variabilele Java s fie folosite direct +n comenzile ")*. .ai observ m c fiecare variabila Java este precedat de dou puncte @8@ i c prin intermediul acestor variabile Java putem e1trage cu uurin rezultatul interog rii, dac ... numai dac rezultatul e1ecuiei comenzii ")* este o reprezentat de o singur linie 6o +nregistrare7K
Componentele SQLJ
n continuare, +n paralel cu e1plicarea pailor pe care#i face/ascunde ")*J vom +ncerca s identific m componentele interne ale ")*J i s vedem rolul pe care#l joac fiecare. 0ranslatorul ")*J Aceast component nu este altceva dec!t un preprocesor sau un precompilator scris complet +n Java, i care este rulat dup ce a fost creat sursa ")*J 6un fisier .sJlj7. 0ranslatorul accept comenzi ")* +n interiorul comenzilor e1ecutabile ")*J. &omenzile e1ecutabile ")*J, ca i declaraiile ")*J, sunt precedate de IsJl i pot fi combinate cu cod Java +n fiierul surs sJlj. ntr#o prim etap translatorul face o analiz sintactic i semantic a comenzilor ")* legate, eventualele erori put!nd fi depistate +nc din aceast faz . Aceasta verificare se poate face conectat sau nu la baza de date 6on-line sau off-line(, +n funcie de opiunile setate. $ac se face o verificare on-line, ")*J se conecteaz la baza de date i verific e1istena tabelelor, a procedurilor stocate i compatibilitatea tipurilor coloanelor referite cu a variabilelor gazd din Java. ,u acelai lucru se +nt!mpl cu codul J$%& care, fiind pur Java, este compilat direct. &ompilatorul nu tie nimic despre ")*, prin urmare erorile ")* nu vor putea fi depistate dec!t la e1ecuie. n faza urm toare translatorul proceseaz codul ")*J, convertete operaiile ")* +n apeluri ")*J runtime, genereaz codul de ieire i unul sau mai multe profile S !J. Dste generat un profil separat pentru fiecare cone1iune, acolo unde se fac cone1iuni 6de e1emplu, la baze de date diferite, sau +n sc(eme diferite7 i fiecare comand ")* va avea mapat o intrare +n profilul generat pentru cone1iunea pe care o folosete. 0ranslatorul genereaz un fiier .java care conine8 # clasele definite i codul Java din fiierul surs .sJlj' # definiiile claselor create ca rezultat al declaraiilor ")*J' # o definiie de clas pentru o clas specializat 6numit i clas profile-)e%7, clase pe care ")*J le creaz i le folosete +n conjuncie cu profilele generate' n final este apelat un compilator Java, care poate fi de e1emplu J$L#ul de la "un i se genereaz c!te un fiier .class pentru fiecare clas definit , c!te un .class pentru fiecare declaraie ")*J i c!te un .class pentru fiecare clas de tip profil c&eie. 4rofilele generate conin informaii despre toate comenzile ")* coninute +n codul surs , tipurile de date care se folosesc i tabelele accesate. &!nd aplicaia ruleaz sunt accesate profilele pentru a se obine operaiile ")* i a le transmite driverului J$%&. Implicit profilele sunt puse +n fiiere de resurse serializate .ser, dar se pot converti +n fiiere .class tot +n procesul de translaie. 6*bserva+ie8 unele broAsere, de e1. ,etscape ,avigator M.1 nu suport fiiere de resurse cu e1tensia ,ser. 4entru a rezolva aceast problem se utilizeaz o opiune de conversie #ser>class care are ca efect conversia resurselor +n fiiere .class7. ")*J runtime &omponenta runtime este apelat de fiecare dat c!nd este rulat o aplicaie ")*J. *a r!ndul ei scris complet +n Java, aceast component implementeaz aciunile descrise de operaiile ")* i acceseaz baza de date folosind un driver J$%&. "tandardul ")*J nu specific ca la rulare s se foloseasc un driver J$%& pentru accesarea bazei de date, +ns -racle ")*J are nevoie de un astfel de driver. &(iar mai mult, este necesar un driver -racle dac aplicaie folosete construcii proprii -racle.
"e pot utiliza cone1iuni diferite la translaie i runtime i asta fiindc aplicaia final va folosi un alt mediu. n acest caz se pot folosi opiuni +n linia de comand +n care se lanseaz +n e1ecuie translatorul 6folosind comanda sJlj7, prin care s se specifice H3*#ul i tipul driverului folosit 6dup opiunea #url7, utilizatorul 6#user7 i parola 6#passAord7. Iteratori Iteratorii sunt folosii pentru recepionarea datelor unei interog ri. Iteratorul trebuie construit +n aa fel +nc!t s fie compatibil cu datele care va trebui s le recepioneze, at!t +n ceea ce privete tipul c!t i num rul c!mpurilor lor. "inta1a folosit va fi8 I")* QmodificatoriCiterator numeRclasaRiteratorEtip declaratiiG' .odificatorii sunt opionali i pot fi orice modificatori Java standard ca8 public, static, etc. "unt dou tipuri de iteratori8 iteratori cu nume i pozi+ionali. n cazul interatorilor cu nume trebuie specificate numele 6identic cu al coloanei de unde se iau datele7 i tipul, care de asemenea trebuie s fie compatibil cu al coloanei respective. IsJl public iterator DmpIter6"tring ename, double sal7' 4entru iteratorii pozi+ionali se va specifica numai tipul coloanelor8 IsJl public iterator DmpIter6"tring, double7' n ambele cazuri translatorul creeaz clasa public DmpIter, cu dou atribute. n declaraia oric rei clase iterator se pot specifica una sau mai multe interfee care vor fi implementate de clasa generat , folosind urm toarea sinta1 8 Isql QmodificatoriC iterator numeRclasaRiterator implements interfata<, interfata>,S interfata, 6declaratii de tip7' i se pot specifica i iniializa una sau mai multe constante care s fie incluse +n definiia clasei generate. &onstantele sunt public static final. "e folosete urm toarea sinta1 8 !sql QmodificatoriC iterator numeRclasaRiterator "it# 6var<9valoare<,S,var,9valoare,7 6declaratii de tip7' *bserva+ie8 &lauzele Ait( i implements sunt plasate +ntotdeauna +naintea declaraiilor de tip. Acolo unde apare i clauza Ait( si implements, clauza implements va fi plasata prima. *ista de dup Ait( va fi prins +ntre paranteze. D1emplu8 IsJl public iterator ./Iter Ait( 60T4D&-$D9-racle0/pes.,H.%D37 6"tring empname, int empnum7' &lasa declarat ./Iter, va avea un atribut 0T4D&-$D care va fi public static final de tip int i iniializat cu valoarea t/pecode pentru tipul de date ,H.%D3 aa cum este definit +n clasa -racle J$%& oracle.jdbc.driver.-racle0/pes. D1emplul urm tor conine at!t clauzele implements c!t i Ait(. IsJl public iterator ./Iter implements m/pacUage../IterIntfc Ait( 6(oldabilit/9true7 6"tring empname, int empnum7' &omenzi ")*J e1ecutabile - comand ")*J e1ecutabil este o comand ")* suportat de driverul J$%& folosit 6comenzi $.*, $$*, sau de control al tranzaciilor7 precedat de clauza ")*J IsJl. &omenzile e1ecutabile trebuie s respecte urm toarele reguli8 # pot s apar n codul Java oriunde este permis un bloc 6deci +n interiorul definiiei metodelor i a blocurilor statice de iniializare7' # trebuie prinse ntre acolade8 E...G. # tot ce este cuprins ntre acolade se consider o comand e-ecutabil S !J i trebuie s respecte regulile de sinta1 ")*, cu e1cepia e1presiilor gazd Java. Iat un e1emplu8 IsJl E ")* operation G' // pentru comenzi care nu au iesire, de e1emplu I,"D30 IsJl result 9 E ")* operation G' // pentru comenzi care au iesire, de e1emplu "D*D&0 *bserva+ie8 ,umai operaiile $.* 6"D*D&0, H4$A0D, I,"D30 i $D*D0D7 pot fi analizate i verificate sintactic de translatorul ")*J, translator folosind cone1iunea la baza de date. &omenzile $$* 6cum sunt &3DA0D ..., sau A*0D3...7, comenzile de control al tranzactiilor 6&-..I0 sau 3-**%A&L7, sau orice alt comand ")* nu va putea fi verificat . 4resupunem c tabela D.4 a fost creat cu comanda8
&3DA0D 0A%*D D.4 6D.4,A.D &VA36:?7,"A*A3T ,H.%D3 7' - comand de inserare +n tabel poate fi8 IsJl E I,"D30 I,0- emp 6empname, salar/7 WA*HD" 6XJoeX, M:???7G' $ac dorim ca operaia de inserare s fie f cut +ntr#o sc(em spre care avem stabilit o alt cone1iune, diferit de cea implicit , cu numele ct1, comanda va fi8 IsJl Oct1P E I,"D30 I,0- emp 6empname, salar/7 WA*HD" 6XJoeX, M:???7 G' n cadrul comenzilor e1ecutabile pot s apar i blocuri 4*/")*, +ntre acolade, e1act ca i orice alt comand ")*. IsJl E $D&*A3D n ,H.%D3' %DYI, n 89 <' WVI*D n Q9 <?? *--4 I,"D30 I,0- emp 6empno7 WA*HD"6>??? F n7' n 89 n F <' D,$ *--4' D,$' G' n interiorul ciclului se insereaz +nregistr rii noi care vor avea +n c!mpul empno valori de la >??< la ><??. n continuare vom lua un alt e1emplu de comand , care folosete e1presii gazd Java precedate de 687. D1presiile gazd sunt folosite pentru transmiterea valorilor +ntre codul Java i comenzile ")*. Acestea pot fi +n cazul cel mai simplu o simpl variabil Java, dar pot s fie i apeluri de metode care returneaz valori, valori ale c!mpurilor clasei, tablouri de elemente, e1presii condiionale de forma 6a B b 8c7, e1presii logice, sau e1presii la nivel de bit 6 bit.ise e-pressions7. Dle pot fi de intrare 6I,7, de ieire 6-H07 sau de intrare#ieire 6I,-H07. IsJl E H4$A0D emp "D0 sal 9 8salar/ WVD3D ename 9 8name G' *bserva+ie8 n ambele cazuri e1presiile Java sunt de tip I,, dar se poate specifica i e1plicit8 IsJl E H4$A0D emp "D0 sal 9 8I, salar/ WVD3D ename 9 8I, name G' &!nd o interogare returneaz o singur linie, ")*J permite specificarea unor variabile gazd Java, +n interiorul comenzii ")*, pentru e1tragerea rezultatului interog rii8 IsJl E "D*D&0 e1pression<,..., e1pression, I,0- 8 (ostRe1p<,..., 8(ostRe1p, 23-. datasource Qoptional clausesC G' $ac comanda "D*D&0 I,0- +ntoarce mai mult de un rezultat se va genera eroare8 "tring empname' ... IsJl E "D*D&0 ename I,0- 8empname 23-. emp WVD3D enum 9 >Z[=[ G' *bserva+ie8 -H0 este implicit pentru o lista I,0-, dar se poate specifica i e1plicit8 IsJl E "D*D&0 ename I,0- 8-H0 empname 23-. emp WVD3D enum 9 >Z[=[G' $e cele mai multe ori interog rile pe o tabel a bazei de date +ntorc mai multe linii ale tabelului. /n acest caz datele vor fi recep+ionate n iteratori, care trebuie mai +nt!i preg tii special, specific!ndu#li#se coloanele i tipul acestora, spre deosebire de obiectul 3esult"et din J$%&, care este instaniat generic. n J$%& clasa java.sJl.3esult"et poate conine, +n principiu, orice num r de coloane de orice tip. IsJl iterator "al,amedIter 6"tring empname, float neAsalar/7 ... class ./&lass E void func67 t(roAs ")*D1ception E ... "al,amedIter niter 9 null' IsJl niter 9 E "D*D&0 name A" empname, oldsal F raise A" neAsalar/ 23-. empsal G' ... G G 4utem declara i un iterator pozitional8 IsJl iterator "al4osIter 6"tring, float7' ...
class ./&lass E void func67 t(roAs ")*D1ception E ... "al4osIter piter 9 null' IsJl piter 9 E "D*D&0 name, oldsal F raise 23-. empsal G' ... G G Iat i c!teva reguli8 # ,u este indicat utilizarea unei sinta1e "D*D&0 5 pentru popularea unui iterator. # n cazul iteratorului poziional num rul de coloane, tipul i ordinea lor din iterator trebuie s coincid cu num rul coloanelor tabelului. # n cazul iteratorilor cu nume este posibil ca num rul coloanelor iteratorului s fie mai mic dec!t al coloanelor tabelului' +n acest caz, dac la translatare nu se folosete opiunea #Aarn9nostrict se va da o atenionare. # Iteratorii poziionali i cei cu nume sunt diferii i incompatibili cu orice tip de clase Java. # Hn iterator de un anumit tip nu poate fi convertit +ntr#un iterator de alt tip' # &oninutul unui iterator, similar cu un set rezultat, este determinat numai de starea bazei de date +n momentul e1ecuiei "D*D&0#ului care#l populeaz ' # Actualiz rile, inserarile, tergerile, commit#urile sau rollbacU#urile nu afecteaz iteratorii sau coninutul lor.
A(ile 6projs.ne1t677 E "/stem.out.println6@4roject name is @ F projs.projname677' "/stem.out.println6@4roject I$ is @ F projs.id677' "/stem.out.println6@4roject deadline is @ F projs.deadline677' G // nc(ide iteratorul projs.close67' ... n cazul iteratorilor poziionali se va specifica numai tipul coloanelor' pentru obinerea datelor din iteratorii poziionali se va folosi comanda 2D0&V..I,0- urmat de un apel al metodei end2etc(67 care va determina dac s#a ajuns la sf!ritul datelor. $e e1emplu8 IsJl public iterator DmpIter 6int, "tring, float7' // $eclar m i iniializ m variabile gazd int id9?' "tring name9null' float salar/9?.?f' DmpIter emps' IsJl emps 9 E "D*D&0 empnum, empname, empsal 23-. emplo/eesG' A(ile 6true7 E IsJl E 2D0&V 8emps I,0- 8id, 8name, 8salar/ G' if 6emps.end2etc(677 breaU' // Acest test trebuie facut dup fetc(, // dar +nainte de procesarea rezultatelor. "/stem.out.println6@,ame is @ F name7' "/stem.out.println6@Dmplo/ee number is @ F id7' "/stem.out.println6@"alar/ is @ F salar/7' ... G emps.close67' ... -bservaii8 # ,u este necesar utilizarea e1plicita a metodei ne1t67 pentru pozitionarea iteratorului, deoarece apelurile 2D0&V mut implicit iteratorul pe urm toarea linie/+nregistrare. # Iniial metoda end2etc(67 returneaz true +nainte ca liniile s fie +nc rcate, iar dup ce o linie a fost +nc rcat cu succes va returna false p!n c!nd i ultima linie va fi +ncarcat , dup care va returna din nou true. # .etoda end2etc(67 trebuie apelat +nainte ca setul rezultat s fie procesat, deoarece 2D0&V nu depisteaz e1cepiile ")* c!nd ajunge la sf!ritul datelor'
"erver include un translator ")*J, ceea ce +nseamn c fiierele surs de pe partea server pot fi translatate direct pe server. n crearea unei aplicaii pentru -racleZi "erver sunt mici diferene +ntre codul care va fi folosit pe partea server i cel de pe client8 # putem avea o singur cone1iune, care trebuie s ofere acces la baza de date +n care codul ruleaz ' # cone1iunea este implicit , aadar nu trebuie specificat e1plicit, # spre deosebire de cone1iunile client, cone1iunea de pe server nu poate fi +nc(is . &odul se poate translata i compila at!t pe partea client cit si pe server. $ac acest lucru este realizat pe client, se pot +nc rca fiierele .class i de resurse de pe server pe propria main , sau folosind translator de pe server. ntrebarea care se pune +n acest moment ar putea fi8 @Dac S !J este mai avanta1os dect JDBC, de ce s mai folosim JDBC"@ n momentul de fa ")*J i J$%& sunt A4I#uri complementare. ")*J poate fi folosit numai pentru ")*#uri statice, deci c!nd comanda ")* este cunoscut +n momentul dezvolt rii. $e regul marea majoritate a comenzilor ")* sunt statice, iar pentru comenzile ")* dinamice, construite +n timpul rul rii, se va folosi J$%&. $in acest punct de vedere nu e1ist probleme fiindc dac este necesar +n interiorul unei aplicaii ")*J se pot folosi i construcii J$%&.
Conclu&ii
4rogramatorii Java au la dispoziie pentru accesarea bazelor de date dou alternative8 J$%& sau ")*J. "ingur J$%& poate fi suficient dar are dou sl biciuni8 # codul este lung i greoi, interog rile realiz!ndu#se destul de dificil' # erorile din interiorul operaiilor ")* nu pot fi depistate dec!t la rulare. ")*J rezolv ambele probleme8 # permite comenzilor ")* cu variabile Java s apar direct +n comenzi ")*J, simplific!nd codul i f c!ndu#l mai clar. # translatorul ")*J verific sinta1a i semantica comenzilor ")*, permi!nd depistarea erorilor +nainte de rulare. n plus, ")*J asigur aceleai verific ri la rulare ca i J$%&. n general J$%& i ")*J vor fi v zute ca te(nologii complementare deoarece8 # ")*J foloseste J$%& pentru a comunica cu baza de date +n timpul translat rii 6dac folosim verific rile online7 i rularii. # J$%& este necesar pentru comenzile ")* dinamice, unde operaiile ")* sunt determinate pe parcursul rul rii aplicaiei' # "e poate mi1a codul aceluiai program +ntre cod J$%& i cod ")*J. Ambele te(nologii pot fi folosite la orice nivel8 # +ntr#un aplet ce foloseste, de e1emplu, un driver t(in J$%&, # +ntr#o aplicaie pe partea client sau # la nivelul din mijloc, folosind un driver t(in sau un driver -racle -&I' # +ntr#o procedura stocat , obiecte &-3%A sau Java%eans care ruleaz +n -racleZi i care folosesc -racle server# side J$%& driver.