Sunteți pe pagina 1din 26

JDBC

JDBC - Java Database Connectivity

 Permite accesul la baze de date din aplicațiile Java

Aplicație Java JDBC API Driver Manager API

JDBC API - specificația Java pentru accesul


la baza de date ...
Oracle SQLS
Driver Manager API - Implementarea API a
driverului bazei de date
Clasificare drivere

Tipuri de drivere:
Nivel 1: Jdbc-Odbc – utilizează puntea Jdbc-Odbc prin mecanismul
ODBC de conectare la o bază de date
Nivel 2: nativ Java API – combină cod nativ cu cod Java pentru
convertirea cererilor JDBC în comenzi proprietar BD
Nivel 3: Database Midleware – drivere pure Java care folosesc un
server middleware pentru conversia cererilor JDBC in comenzi
DBMS. Serverul lucrează cu diverse tipuri de baze de date. Nu mai
există cod nativ pe partea de client
Nivel 4: Pure Java Driver – conectare directă la BD prin cod Java
utilizând un protocol specific bazei de date
Aplicatie Java Aplicatie Java Aplicatie Java Aplicatie Java

JDBC Api JDBC Api JDBC Api JDBC Api

JDBC DriverManager JDBC DriverManager JDBC DriverManager JDBC DriverManager

Driver Java Driver Java Driver Java Driver Java

Driver ODBC Cod nativ Server Midleware


DBMS

Cod nativ
DBMS

DBMS
Accesarea unei baze de date utilizând JDBC

Elementele unei aplicații utilizând JDBC pentru conectare:


 Crearea conexiunii la baza de date
 Interogarea bazei de date
 Procesarea rezultatelor
 Închiderea conexiunii
Crearea conexiunilor la baza de date
 Conexiunile se creează utilizând un protocol de conectare:
jdbc:subprotocol:BazaDeDate
Exemple:
"jdbc:odbc:legatura" - protocol de conectare pentru ODBC utilizând o legătura ODBC
configurata Windows
"jdbc:sqlserver://host\\server:1433;database=baza;user=sa;password=parola;"
"jdbc:mysql://host:3306/baza"
"jdbc:oracle:thin:@ip-host:1521:instanta"
'"dbc:derby://host:1527/sample"
unde host este ip-ul mașinii pe care este instalat serverul DB
Referințele la conexiuni sunt obținute prin invocarea metodelor statice getConnection
din DriverManager
public static Connection getConnection(String url) throws SQLException;
public static Connection getConnection(String url, String user, String password) throws
SQLException
Interogarea – Obiecte Statement

 Sunt obiecte utilizate pentru executarea instrucțiunilor SQL


 Executarea instrucțiunilor de bază este realizată prin implementarea
interfeței Statement și interfețelor derivate din aceasta
public interface Statement; // Executarea instrucțiunilor statice

 Pentru executarea instrucțiunilor precompilate se utilizează


PreparedStatement:
public interface PreparedStatement extends Statement;

 Pentru executarea procedurilor stocate:


public interface CallableStatement extends PreparedStatement;
Crearea obiectelor Statement
• Crearea obiectelor Statement se face prin următoarele metode ale interfeței
Connection:
Statement createStatement() throws SQLException;
Statement createStatement(int resultSetType, int resultSetConcurrency) throws
SQLException;
Statement createStatement(int resultSetType, int resultSetConcurrency,
int resultSetHoldability) throws SQLException;
• Comenzile Statement creează un rezultat, care pentru o interogare este o structură
tabelară cu rezultatul interogării
• Rezultatul interogărilor este gestionat prin obiecte ResultSet
public interface ResultSet extends Wrapper, AutoCloseable;
• Obiectele ResultSet gestionează un cursor - pointer la rândurile structurii tabelare
rezultate prin interogare
• Proprietățile cursorului sunt definite prin parametrii metodelor createStatement
 Semnificația parametrilor createStatement:
- resultSetType - tipul cursorului (deplasabil/nedeplasabil, senzitiv/nesenzitiv). Un
cursor deplasabil permite poziționarea pointerului pe un rând folosind indexul
rândului. Un cursor senzitiv permite modificări simultane în cursor și în tabela
sursă.
ResultSet.TYPE_FORWARD_ONLY; //nedeplasabil, nesenzitiv
ResultSet.TYPE_SCROLL_INSENSITIVE; //deplasabil, nesenzitiv
ResultSet.TYPE_SCROLL_SENSITIVE; //deplasabil, senzitiv
- resultSetConcurrency - permisiune modificări concurente (nu/da)
ResultSet.CONCUR_READ_ONLY; //nu permite acces concurențial
ResultSet.CONCUR_UPDATABLE ; //permite acces concurențial
- resultSetHoldability - menținere cursor după efectuarea (comiterea) tranzacțiilor
(nu/da)
ResultSet.HOLD_CURSORS_OVER_COMMIT; // menține cursorul
ResultSet.CLOSE_CURSORS_AT_COMMIT; //închide cursorul
 Menținerea cursorului (holdability) poate fi reglementată și prin metode
Connection:
void setHoldability (int holdability) throws SQLException; // se specifică unul
din cei doi parametri

 Testarea cursorului:
int getHoldability() throws SQLException; // rezultatul este unul din cei doi
parametri
Gruparea comenzilor - Tranzacții

Gruparea comenzilor prin obiectele Statement


 void addBatch(String sql) throws SQLException; //metodă prin care se adaugă la
obiectul curent comanda specificata
 void clearBatch() throws SQLException; //Șterge comenzile din lista de comenzi
 int[] executeBatch() throws SQLException; // Executare comenzi adăugate.
Întoarce un int pentru fiecare comanda in ordinea adăugării lor. Respectiva
valoare poate fi:
>=0 in funcție de numărul tuplurilor afectate(vezi executeUpdate),
SUCCESS_NO_INFO - comanda s-a executat cu succes dar nu se cunoaște
numărul tuplurilor afectate
EXECUTE_FAILED - execuția comenzii a eșuat. Executarea comenzilor
următoare poate fi întrerupta sau nu la eșec (in funcție de driver)
Modul commit este legat de efectul definitiv al comenzilor. Este gestionat prin
următoarele metode Connection:

 void setAutoCommit(boolean autoCommit) throws SQLException;


//stabilește modul commit (true, false). Implicit este true, adică orice
comanda este executata individual si definitiv
 boolean getAutoCommit() throws SQLException ; //întoarce modul
commit existent
 void commit() throws SQLException ; // declanșează salvarea permanenta
a modificărilor apărute in DB.
 void rollback() throws SQLException; //anularea modificărilor
Metodele commit si rollback marchează terminarea tranzacției curente.
Niveluri de izolare pentru tranzacții

 Asigura izolarea tranzacțiilor unele față de celelalte si partajarea resurselor


intre utilizatori concurenți astfel încât să fie evitate anomaliile în baza de
date. Metode de stabilire/citire nivel:
void setTransactionIsolation(int level) throws SQLException
int getTransactionIsolation() throws SQLException

Anomalii de executie concurenta a tranzactiilor


 Citire improprie (dirty read). Această anomalie poate să apară atunci când
una din tranzacții este abandonată, iar altă tranzacție concurentă a utilizat
articolele modificate, înainte de readucerea acestora la valoarea inițială.
 Citire irepetabilă (nonrepetable read). Poate să apară dacă o tranzacție T1
citește un articol de două ori, iar între cele două citiri, o altă tranzacție T2 a
modificat chiar acel articol. În această situație tranzacția T1 primește două
valori diferite ale aceluiași articol.
 Citire fantomă (phantom read). Apare atunci când o tranzacție prelucrează un set
de linii rezultat al unei interogări. Dacă în timpul acestei prelucrări o alta
tranzacție a inserat sau a șters o linie care satisface condiția interogării respective,
atunci pot sa apară sau sa dispară linii din mulțimea de linii rezultat - linii
fantomă.

Niveluri de izolare:
 static final int TRANSACTION_NONE; // nu sunt permise tranzacțiile
 static final int TRANSACTION_READ_UNCOMMITTED; // fără izolare
 static final int TRANSACTION_READ_COMMITTED; // Este legat de
paradigma citirilor improprii - Dirty Reads. Nivelul trebuie sa înlăture aceste
situații. Soluție: nu sunt citite date care au fost modificate si nu s-au definitivat
modificările prin commit()
 static final int TRANSACTION_REPEATABLE_READ; // Este legat de
paradigma “citirilor nerepetabile” - Non-Repeatable Reads. Comenzi
identice de citire dau rezultate diferite in cadrul aceleiași tranzacții.
Soluție: interzice unei tranzacții sa citească din nou date dintr-un rând care
a fost modificat definitiv prin commit() de către o alta tranzacție.
 static final int TRANSACTION_SERIALIZABLE; // Elimină și riscurile
create de problema “fantomei” - Phantom Reads. Problema fantomei apare
când o tranzacție inserează/șterge înregistrări selectabile într-o selecție a
altei tranzacții. Soluție: izolarea completa - tranzacțiile sunt serializate.
Exemple
Presupunem că avem o tabelă studenti cu câmpurile nume și media
nume media
Ionescu Dan 9
Popescu Maria 9.33

Dirty Reads
Tranzacția A
UPDATE studenti SET media = 9.5 WHERE nume='Ionescu Dan'
Tranzacția B
SELECT * FROM studenti
Tranzacția A
rollback

Rezultat: Tranzacția B folosește date invalide. Tranzacția A nu a definitivat


modificările prin commit
Non-Repeatable Reads

Tranzacția A
SELECT * FROM studenti WHERE nume = 'Popescu Maria'
Tranzacția B
UPDATE studenti SET media = 8.50 WHERE nume = 'Popescu Maria'
commit
Tranzacția A
SELECT * FROM studenti WHERE nume = 'Popescu Maria'
commit

Tranzacția B actualizează rândul interogat de A înainte ca A să invoce commit, astfel


încât la următoarele interogări identice ale lui A rezultatul va fi diferit.
Phantom Reads

Tranzacția A
SELECT * FROM studenti WHERE media > 7
Tranzacția B
INSERT INTO studenti VALUES ('Popa Leon', 7.5)
commit
Tranzacția A
SELECT * FROM studenti WHERE media > 7
commit

Tranzacția B inserează un rând care satisface criteriile de interogare din A dar care nu
apare decât la a doua interogare. Acesta se numește "rând fantomă".
Comenzi precompilate

Sunt comenzi compilate si memorate in stare compilata la nivelul serverului DB.


Executarea lor nu mai necesita recompilare. Sunt folosite pentru executarea repetata
a unor operațiuni.
PreparedStatement prepareStatement(String sql) throws SQLException;
PreparedStatement prepareStatement(String sql, int resultSetType,
int resultSetConcurrency) throws SQLException;
PreparedStatement prepareStatement(String sql, int resultSetType,
int resultSetConcurrency, int resultSetHoldability) throws SQLException;

PreparedStatement statement = c.prepareStatement("update catalog set nota=? where


nume=?");
statement.setInt(1, 8);
statement.setString(2,’Ionescu Diana’);
statement.executeUpdate();
 Executarea procedurilor stocate se realizează prin metode prepareCall ale
obiectului Connection:
CallableStatement prepareCall(String sql, int resultSetType,
int resultSetConcurrency, int resultSetHoldability) throws SQLException;
CallableStatement prepareCall(String sql, int resultSetType,
int resultSetConcurrency) throws SQLException;
CallableStatement prepareCall(String sql) throws SQLException;
 Parametri au aceeași semnificație ca la metodele createStatement
Procesarea rezultatelor

Procesarea rezultatelor unei interogări se face prin comenzi ResultSet.

 boolean next() throws SQLException; // trecere pointer la rând nou


 boolean absolute(int row) throws SQLException; // poziționare absoluta pe rândul
specificat
 boolean relative(int rows) throws SQLException; // poziționare relativa pe un rând
(fata de poziția curenta)
 boolean previous() throws SQLException; // trecere pointer la rândul anterior
 void afterLast() throws SQLException; // poziționare după ultimul rând
 boolean first() throws SQLException; // încercare de poziționare pe primul rând
 boolean last() throws SQLException; // încercare de poziționare pe ultimul rând
 void beforeFirst() throws SQLException; // trecere pointer înaintea primului rând
 boolean isLast() throws SQLException; // test poziționare pe ultimul rând
 boolean isFirst() throws SQLException;// test poziționare pe primul rând
 boolean isAfterLast() throws SQLException ;// test poziționare după ultimul
 boolean isBeforeFirst() throws SQLException; // test poziționare înaintea primului
rând
 void deleteRow() throws SQLException ; // ștergere rând
 void refreshRow() throws SQLException ; // actualizare rând curent cu valorile din
DB. Nu poate fi aplicat rândului de inserție.
 void updateRow() throws SQLException ; //actualizare valori din DB cu cele din
rândul curent
 void insertRow() throws SQLException; // adăugare valori din rândul de inserție la DB
 void moveToInsertRow() throws SQLException;// trecere pe rândul de inserție
 void moveToCurrentRow() throws SQLException ; // Se aplică pe rândul de inserție si
are ca efect trecerea pe rândul curent (cel pe care se afla cursorul înainte de inserție)
 Tip getTip(int columnIndex) throws SQLException; // preluare valoare din rând
conform cu tipul si numărul coloanei
 Tip getTip(String columnLabel) throws SQLException;// preluare valoare din rând
conform cu tipul si numele coloanei
 void updateTip(int columnIndex, Tip x) throws SQLException; // actualizare rând cu
valoarea specificată pentru coloana specificată
 void updateTip(String columnLabel, Tip x) throws SQLException;// idem
Maparea între tipuri

 Într-o aplicație JDBC se lucrează cu trei tipuri de date: tipurile Java, tipurile JDBC,
tipurile SQL (in dialectul corespunzător).
 Tipurile JDBC sunt descrise in clasa java.sql.Types sub forma de câmpuri statice int -
BOOLEAN, DATE, DOUBLE etc.
 Corespondenta dintre tipuri se face voluntar prin codul aplicației cunoscând
semnificația tipurilor
 Prin metoda de instanță a clasei ResultSetMetaData:
int getColumnType(int column) throws SQLException;
se poate obține un tip din Types corespunzător coloanei investigate.
Tipul dată:
public class java.sql.Date extends java.util.Date; // clasa destinată să modeleze data
calendaristica in aplicațiile JDBC
public static Date valueOf(String s); // convertește un String de forma "yyyy-[M]M-[d]d"
in data JDBC
public String toString(); // convertește o data într-un sir in format "yyyy-[M]M-[d]d"
Operațiuni CRUD (Create Read Update Delete) pe ResultSet
 Inserare de noi rânduri
Trecerea pe rândul de insert
r.moveToInsertRow();
Operațiuni de inițializare câmpuri
r.updateTip(nrColoana, valoare);

Adăugarea rândului
r.insertRow();
 Actualizare
r.absolute(i); // trecere pe rândul i
r.updateTip(nrColoana, valoare); // actualizare pe coloana nrColoana

r.updateRow(); // inserarea noilor valori
 Ștergere
r.absolute(i); // trecere pe rândul dorit
r.deleteRow(); // ștergere
Accesul la metadate
 Accesul la metadate prin obiecte Connection - sunt furnizate informații despre baza de
date (structura, tabele/viziuni, catalog etc.)
String getCatalog() throws SQLException; //Întoarce numele de catalog
void setCatalog(String catalog) throws SQLException
DatabaseMetaData getMetaData() throws SQLException; //Întoarce obiect cu
informații de tip metadată la nivelul bazei de date
 Furnizarea numelor de tabele și viziuni se face prin metoda getTables a clasei
DatabaseMetaData:
ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern,
String[] types) throws SQLException; // Numele de catalog și de schemă pot fi null.
tableNamePattern este numele tabelei sau o parte din nume, types este un vector de
șiruri care pot fi: "TABLE", "VIEW", "SYSTEM TABLE", "GLOBAL
TEMPORARY", "LOCAL TEMPORARY", "ALIAS", "SYNONYM"
Metoda întoarce un obiect ResultSet cu informații privind obiectele interogate (tabele,
viziuni etc). Coloanele obiectului ResultSet cuprind numele de catalog, schema, numele
obiectului (nume de tabelă, viziune etc.), tipul obiectului (tabelă, viziune etc.) etc.
Numele de obiect este coloana 3 sau coloana cu numele "TABLE_NAME".
 Accesul la metadate prin obiecte ResultSet - sunt furnizate informații despre setul
interogat (coloane, tipuri, dimensiuni câmp etc.). Informațiile sunt memorate prin
obiecte din clasa ResultSetMetaData. Un obiect ResultSetMetaData se obține prin
metoda getMetaData a interfeței ResultSet:
ResultSetMetaData getMetaData() throws SQLException;
 Accesul la informații se face prin metodele ResultSetMetaData:
int getColumnCount() throws SQLException
String getColumnName(int column) throws SQLException
int getColumnType(int column) throws SQLException
String getColumnTypeName(int column) throws SQLException
int getColumnDisplaySize(int column) throws SQLException

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