CATEGORII DOCUMENTE |
JDBC
JDBC (Java Database Connectivity) este o interfata standard SQL de acces la baze de date fiind constituita dintr-un set de clase si interfete scrise in Java, furnizand mecanisme standard pentru proiectantii aplicatiilor ce folosesc de baze de date.
Folosind JDBC este usor sa transmitem secvente SQL catre baze de date relationale. Este de ajuns sa scriem un singur program folosind API-ul JDBC si acesta va fi capabil sa comunice cu drivere diferite, trimitand secvente SQL catre baza de date dorita. Bineinteles, scriind codul sursa in Java, ne este asigurata portabilitatea programului. Deci, iata doua motive puternice care fac combinatia Java - JDBC demna de luat in seama.
Pachetele care ofera suport pentru lucrul cu baze de date sunt java.sql ce reprezinta nucleul tehnologiei JDBC si, preluat de pe platforma J2EE, javax.sql.
API-ul JDBC ofera urmatoarele facilitati:
1. Stabilirea unei conexiuni cu o baza de date.
2. Efectuarea de secvente SQL.
3. Prelucrarea rezultatelor obtinute.
Conectarea la o baza de date
Procesul de conectare la o baza de date implica efectuarea a doua operatii:
1. Inregistrarea unui driver corespunzaator.
2. Realizarea unei conexiuni propriu-zise.
Definitie
O conexiune (sesiune) la o baza de date reprezinta un context prin care sunt trimise secvente SQL si primite rezultate. Intr-o aplicatie pot exista simultan mai multe conexiuni la baze de date diferite sau la aceeasi baza.
Clasele si interfetele responsabile cu realizarea unei conexiuni sunt:
. DriverManager - este clasa ce se ocupa cu inregistrarea driverelor ce vor fi folosite in aplicatie;
. Driver - interfata pe care trebuie sa o implementeze orice clasaa ce descrie un driver;
. DriverPropertyInfo - prin intermediul acestei clase pot fi specificate diverse proprietati ce vor fi folosite la realizarea conexiunilor;
. Connection - descrie obiectele ce modeleazaa o conexiune propriu-zisaa cu baza de date.
Inregistrarea unui driver
Primul lucru pe care trebuie sa-l faca o aplicatie in procesul de conectare la o baza de date este sa inregistreze la masina virtuala ce ruleaza aplicatia driverul JDBC responsabil cu comunicarea cu respectiva bazaa de date. Acest lucru presupune incarcarea in memorie a clasei ce implementeaza driver-ul si poate fi realizata in mai multe modalitati.
a.
Folosirea clasei DriverManager:
DriverManager.registerDriver(new TipDriver());
b. Folosirea metodei Class.forName ce apeleaza
ClassLoader-ul masinii
virtuale:
Class.forName('TipDriver'); Class.forName('TipDriver').newInstance();
c. Setarea proprietatii sistem jdbc.drivers, care poate fi
realizata in doua
feluri:
- De la linia de comanda:
java -Djdbc.drivers=TipDriver Aplicatie
- Din program:
System.setProperty('jdbc.drivers', 'TipDriver');
Folosind aceasta metoda, specificarea mai multor drivere se face separand numele claselor cu punct si virgula.Daca sunt inregistrate mai multe drivere, ordinea de precedenta in alegerea driverului folosit la crearea unei noi conexiuni este:
Specificarea unei baze de date
O data ce un driver JDBC a fost inregistrat, acesta poate fi folosit la stabilirea unei conexiuni cu o bazaa de date. Avand in vedere faptul ca pot exista mai multe drivere incarcate in memorie, trebuie sa avem posibilitea de a specifica pe langa un identificator al bazei de date si driverul ce trebuie folosit. Aceasta se realizeaza prin intermediul unei adrese specifice, numita JDBC URL, ce are urmaatorul format:
jdbc:sub-protocol:identificator DB
Campul sub-protocol denumeste tipul de driver ce trebuie folosit pentru realizarea conexiunii si poate fi odbc, Microsoft SQL, Oracle, sybase, db2 si asa mai departe.
Identificatorul bazei de date este un indicator specific fiecarui driver corespunzator bazei de date cu care aplicatia doreste sa interactioneze. In functie de tipul driver-ului acest identificator poate include numele unei masini gazda, un numar de port, numele unui fisier sau al unui director, etc., La primirea unui JDBC URL, DriverManager-ul va parcurge lista driverelor inregistrate in memorie, pana cand unul dintre ele va recunoaste URL-ul respectiv. Daca nu exista nici unul potrivit, atunci va fi lansata o exceptie de tipul SQLException, cu mesajul 'no suitable driver'.
Realizarea unei conexiuni
Metoda folosita pentru realizarea unei conexiuni este getConnection din clasa DriverManager si poate avea mai multe forme:
Connection c = DriverManager.getConnection(url);
Connection c = DriverManager.getConnection(url, username, password); Connection c = DriverManager.getConnection(url, dbproperties);
Stabilirea unei conexiuni folosind un driver
Folosirea diferitelor tipuri de drivere implica doar schimbarea numelui clasei ce reprezinta driverul si a modalitatii de specificare a bazei de date.
String url = 'jdbc:sqlserver://localhost/test' ;
// sau url = 'jdbc:sqlserver://localhost/test?user=..&password=..';
try catch(ClassNotFoundException e)
if(rowCount = 0)
// rowCount este -1
// Avem unul sau mai multe ResultSet-uri ResultSet rs = stmt.getResultSet(); if(rs != null)
//Nu mai avem nici un rezultat break;
}
Folosind clasa Statement, in cazul in care dorim sa introducem valorile unor variabile intr-o secventa SQL, nu avem alta solutie decat sa cream un sir de caractere compus din instructiuni SQL si valorile variabilelor:
int cod = 100;
String nume = 'Popescu';
String sql = 'SELECT * FROM persoane WHERE cod=' + cod +
' OR nume='' + nume + ResultSet rs = stmt.executeQuery(sql);
Interfata PreparedStatement
Interfata PreparedStatement este derivata din Statement, fiind diferita de aceasta in urmatoarele privinte:
. Instantele de tip PreparedStatement contin secvente SQL care au fost deja compilate (sunt 'pregatite').
. O secventa SQL specificata unui obiect PreparedStatement poate sa aiba unul sau mai multi parametri de intrare, care vor fi specificati prin intermediul unui semn de intrebare ('?') in locul fiecaruia dintre ei. Inainte ca secventa SQL sa poata fi executata fiecarui parametru de intrare trebuie sa i se atribuie o valoare, folosind metode specifice acestei clase.
Executia repetata a aceleiasi secvente SQL, dar cu parametri diferiti, va fi in general mai rapida daca folosim PreparedStatement, deoarece nu mai trebuie sa cream cate un obiect de tip Statement pentru fiecare apel SQL, ci refolosim o singura instanta precompilata furnizandu-i doar alte argumente.
Crearea unui obiect de tip PreparedStatement se realizeazaa prin intermediul metodei prepareStatement a clasei Connection, specifican ca argument o secventa SQL ce contine cate un semn de intrebare pentru fiecare parametru de intrare:
Connection con = DriverManager.getConnection(url); String sql = 'UPDATE persoane SET nume=? WHERE cod=?'; Statement pstmt = con.prepareStatement(sql);
Obiectul va pstmt contine o comanda SQL precompilata care este trimisa imediat catre baza de date, unde va astepta parametri de intrare pentru a putea fi executata.
Trimiterea parametrilor se realizeaza prin metode de tip setXXX, unde XXX este tipul corespunzator parametrului, iar argumentele metodei sunt numarul de ordine al parametrului de intrare (al semnului de intrebare) si valoarea pe care dorim sa o atribuim.
pstmt.setString(1, 'Ionescu'); pstmt.setInt(2, 100);
Dupa stabilirea parametrilor de intrare secventa SQL poate fi executata. Putem apoi stabili alte valori de intrare si refolosi obiectul PreparedStatement pentru executii repetate ale comenzii SQL. Este insa posibil ca SGBD-ul folosit sa nu suporte acest tip de operatiune si sa nu retina obiectul pre-compilat pentru executii ulterioare. In aceasta situatie folosirea interfetei PreparedStatement in loc de Statement nu va imbunatati in nici un fel performanta codului, din punctul de vedere al vitezei de executie a acestuia.
Executia unei secvente SQL folosind un obiect PreparedStatement se realizeaza printr-una din metodele executeQuery, executeUpdate sau execute, semnificatiile lor fiind aceleasi ca si in cazul obiectelor de tip Statement, cu singura deosebire ca in cazul de fata ele nu au nici un argument.
String sql = 'UPDATE persoane SET nume=? WHERE cod=?'; Statement pstmt = con.prepareStatement(sql); pstmt.setString(1, 'Ionescu'); pstmt.setInt(2, 100); pstmt.executeUpdate();
pstmt.setString(1, 'Popescu'); pstmt.setInt(2, 200); pstmt.executeUpdate();
sql = 'SELECT * from persoane WHERE cod >= ?'; pstmt = con.prepareStatement(sql); pstmt.setInt(1, 100); ResultSet rs = pstmt.executeQueryO;
Tipuri de date. Fiecarui tip Java ii corespunde un tip generic SQL. Este responsabilitatea programatorului sa se asigure ca foloseste metoda adecvata de tip setXXX la stabilirea valorii unui parametru de intrare. Lista tuturor tipurilor generice disponibile, numite si tipuri JDBC, este definita de clasa Types, prin constantelor declarate de aceasta. Metoda setObject permite specificarea unor valori pentru parametrii de intrare, atunci cand dorim saa folosim maparea implicita intre tipurile Java si cele JDBC sau atunci cand dorim sa precizam explicit un tip JDBC.
pstmt.setObject(1, 'Ionescu', Types.CHAR); pstmt.setObject(2, 100, Types.INTEGER); // sau doar pstmt.setObject(2, 100);
Folosind metoda setNull putem sa atribuim unui parametru de intrare valoare SQL NULL, trebuind insa sa specificam si tipul de date al coloanei in care vom scrie aceasta valoare. Acelasi lucru poate fi realizat cu metode de tipul setXXX dacaa argumentul folosit are valoarea null.
pstmt.setNull(1, Types.CHAR); pstmt.setInt(2, null);
Cu ajutorul metodelor setBytes sau setString avem posibilitatea de a specifica date de orice dimensiuni ca valori pentru anumite articole din baza de date. Exista insa situatii cand este de preferat ca datele de mari dimensiuni sa fie transferate pe 'bucati' de o anumita dimensiune. Pentru a realiza acest lucru API-ul JDBC pune la dispozitie metodele setBinaryStream, setAsciiStream si setUnicodeStream care ataseaza un flux de intrare pe octeti, caractere ASCII, respectiv UNICODE, unui parametru de intrare. Pe masura ce sunt citite date de pe flux, ele vor fi atribuite parametrului. Exemplul de mai jos ilustreaza acest lucru, atribuind coloanei continut continutul unui anumit fisier:
File file = new File('date.txt');
int fileLength = file.length();
InputStream fin = new FileInputStream(file);
java.sql.PreparedStatement pstmt = con.prepareStatement(
'UPDATE fisiere SET continut = ? WHERE nume = 'date.txt''); pstmt.setUnicodeStream (1, fin, fileLength); pstmt.executeUpdate();
La executia secventei, fluxul de intrare va fi apelat repetat pentru a furniza datele ce vor fi scrise in coloana continut a articolului specificat. Observati ca este necesar ina sa stim dinainte dimensiunea datelor ce vor fi scrise, acest lucru fiind solicitat de unele tipuri de baze de date.
Interfata CallableStatement
Interfata CallableStatement este derivata din PreparedStatement, instantele de acest tip oferind o modalitate de a apela o procedura stocata intr-o bazaa de date, intr-o maniera standard pentru toate SGBD-urile.
Crearea unui obiect CallableStatement se realizeazaa prin metoda prepareCall a clasei Connection:
Connection con = DriverManager.getConnection(url); CallableStatement cstmt = con.prepareCall( '');
Trimiterea parametrilor de intrare se realizeaza intocmai ca la PreparedStatement, cu metode de tip setXXX. Daca procedura are si parametri de iesire (valori returnate), acestia vor trebui inregistrati cu metoda registerOutParameter inainte de executia procedurii. Obtinerea valorilor rezultate in parametrii de iesie se va face cu metode de tip getXXX.
CallableStatement cstmt = con.prepareCall(
''); cstmt.registerOutParameter(1, java.sql.Types.FLOAT); cstmt.executeQueryO; float medie = cstmt.getDouble(l);
Este posibil ca un parametru de intrare sa fie si parametru de iesire. In acest caz el trebuie sa primeasca o valoare cu setXXX si, de asemenea, va fi inregistrat cu registerOutParameter, tipurile de date specificate trebuind sa coincida.
Obtinerea si prelucrarea rezultatelor. Interfata ResultSet
In urma executie unei interogari SQL rezultatul va fi reprezentat printr-un obiect de tip ResultSet, ce va contine toate liniile ce satisfac conditiile impuse de comanda SQL. Forma generala a unui ResultSet este tabelara, avand un numar de coloane si de linii, functie de secventa executata. De asemenea, obiectul va contine si meta-datele interogarii cum ar fi denumirele coloanelor selectate, numaarul lor, etc.
Statement stmt = con.createStatement(); String sql = 'SELECT cod, nume FROM persoane'; ResultSet rs = stmt.executeQuery(sql);
Pentru a extrage informatiile din aceasta structura va trebui sa parcurgem tabelul linie cu linie si din fiecare sa extragem valorile de pe coloane. Pentru acest lucru vom folosi metode de tip getXXX, unde XXX este tipul de data al unei coloane iar argumentul primit indica fie numarul de ordine din cadrul tabelului, fie numele acestuia. Coloanele sunt numerotate de la stanga la dreapta, incepand cu 1. In general, folosirea indexului coloanei in loc de numele sau va fi mai eficienta. De asemenea, pentru maxima portabilitate se recomanda citirea coloanelor in ordine de la stanga la dreapta si fiecare citire saa se facaa o singuraa dataa.
Un obiect ResultSet foloseste un cursor pentru a parcurge articolele rezultate in urma unei interogari. Initial acest cursor este pozitionat inaintea primei linii, fiecare apel al metodei next determinand trecerea la urmatoarea linie. Deoarece next returneaza false cand nu mai sunt linii de adus, uzual va fi folosita o bucla while-loop petru a itera prin articolele tabelului:
String sql = 'SELECT cod, nume FROM persoane'; ResultSet rs = stmt.executeQuery(sql); while (rs.next())
Implicit, un tabel de tip ResultSet nu poate fi modificat iar cursorul asociat nu se deplaseaza decat inainte, linie cu linie. Asadar, putem itera prin rezultatul unei interogari o singura data si numai de la prima la ultima linie. Este insa posibil sa cream ResultSet-uri care sa permita modificarea sau deplasarea in ambele sensuri.
Exemplul urmator va folosi un cursor care este modificabil si nu va reflecta schimbarile produse de alti utilizatori dupa crearea sa:
Statement stmt = con.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE); String sql = 'SELECT cod, nume FROM persoane'; ResultSet rs = stmt.executeQuery(sql);
Daca un ResultSet foloseste un cursor modificabil si care poate naviga in ambele sensuri, atunci are la dispozitie o serie de metode ce se bazeaza pe acest suport:
. absolute - Deplaseaza cursorul la o anumita linie specificata absolut;
. updateXXX - Actualizeaza valoarea unei coloane din linia curenta, unde XXX este un tip de date.
. updateRow - Transfera actualizarile facute liniei in baza de date.
. moveToInsertRow - deplaseaza cursorul la o linie spceiala, numita linie nouaa, utilizateaa pentru a introduce noi articole in baza de date. Linia curenta anterioara a cursorului va fi memorata pentru a se putea reveni la ea.
. insertRow - insereaza articolul din zona linie noua in baza de date; cursorul trebuie sa fie pozitionat le linia noua la executia acestei operatiuni.
. moveToCurrentRow - revine la linia curentaa din tabel.
. deleteRow - sterge linia curenta din tabel si din baza de date; nu poate fi apelata cand cursorul este in modul linie noua.
Nu toate sistemele de gestiune a bazelor de date ofera suport pentru folosirea cursoarelor care pot fi modificate.Pentru a determina daca baza de date permite acest lucru pot fi utilizate metodele supportsPositionedUp-date si supportsPositionedDelete ale clasei DatabaseMetaData. In cazul in care acest lucru este permis, este responsabilitatea driver-ului bazei de date sa asigure rezolvarea problemelor legate de actualizarea concurentaa a unui cursor, astfel incat sa nu apara anomalii.
Linkuri utile JDBC
https://72.5.124.55/docs/books/tutorial/jdbc/TOC.html
si https://72.5.124.55/docs/books/tutorial/jdbc/basics/running.html - cod complet aplicatie
pentru dezvoltarea de aplicatii Php/Mysql folosind Netbeans
www.netbeans.org/kb/docs/ide/mysql.html
https://www.netbeans.org/kb/trails/php.html
Politica de confidentialitate | Termeni si conditii de utilizare |
Vizualizari: 2711
Importanta:
Termeni si conditii de utilizare | Contact
© SCRIGROUP 2024 . All rights reserved