Documente Academic
Documente Profesional
Documente Cultură
INTRODUCERE
Aplicaţiile care folosesc baze de date sunt, în general, aplicaţii complexe folosite
pentru gestionarea unor informaţii de dimensiuni mari într-o manieră sigură şi eficientă.
Crearea unei baze de date
Crearea unei baze de date se face uzual folosind aplicaţii specializate oferite de
producătorul tipului respectiv de sistem de gestiune a datelor.
Accesul la baza de date
Se face prin intermediul unui driver specific tipului respectiv de SGBD. Acesta
este responsabil cu accesul efectiv la datele stocate, fiind legatura dintre aplicaţie şi
baza de date.
Limbajul SQL
SQL (Structured Query Language) reprezintă un limbaj de programare ce permite
interogarea şi actualizarea informaţiilor din baze de date relaţionale. Acesta este
standardizat astfel încât diverse tipuri de drivere să se comporte identic, oferind astfel o
modalitate unitară de lucru cu baze de date.
Interfaţă Descriere
DatabaseMetaData Interfaţă folosită de către cei care produc drivere
pentru a informa utilizatorii despre capabilităţile
oferite de DBMS-uri împreună cu driverul JDBC
folosit.
ParameterMetaData Interfaţă folosită pentru a obţine informaţii despre
tipurile şi proprietăţile parametrilor dintr-un obiect
PreparedStatement.
ResultSetMetaData Interfaţă folosită pentru a obţine informaţii despre
tipurile şi proprietăţile coloanelor dintr-un ResultSet.
Pachetele care oferă suport pentru lucrul cu baze de date sunt java.sql ce
reprezintă nucleul tehnologiei JDBC şi javax.sql preluat de pe platforma J2EE. Ceea ce
trebuie remarcat este faptul că aplicaţiile care folosesc baze de date trebuie să includă
pachetul java.sql, şi nu pachetul care conţine implementarea driverului particular folosit.
Totuşi, calea spre pachetul conţinând driverul trebuie sa fie prezentă în CLASSPATH.
Interfaţa DatabaseMetaData
După realizarea unui conexiuni la o bază de date, putem apela metoda
getMetaData pentru a afla diverse informaţii legate de baza respectivă. Ca rezultat al
apelului metodei, vom obţine un obiect de tip DatabaseMetaData ce oferă metode pentru
determinarea tabelelor, procedurilor stocate, capabilităţilor conexiunii, gramaticii SQL
suportate, etc. ale bazei de date.
Programul următor afişează numele tuturor tabelelor dintr-o bază de date
înregistrată în ODBC:
import java.sql.*;
public class TestMetaData {
public static void main ( String [] args ) {
String url = "jdbc:odbc:test";
try {
Class.forName ("sun.jdbc.odbc.JdbcOdbcDriver");
} catch ( ClassNotFoundException e) {
System.out.println (" Eroare incarcare driver !\n" + e);
return ;
}
try {
Connection con = DriverManager.getConnection (url);
DatabaseMetaData dbmd = con.getMetaData ();
ResultSet rs = dbmd.getTables (null , null , null , null );
while (rs.next ())
System.out.println (rs. getString (" TABLE_NAME "));
con.close ();
} catch ( SQLException e) {
e.printStackTrace ();
}
} }
Interfaţa ParameterMetaData
Metoda getMetaData a clasei PreparedStatement recuperează obiectul
ResultSetMetaData care conţine o descriere a coloanelor care vor fi întoarse când se
execută PreparedStatement. Metoda getParameterMetaData() întoarce un obiect
ParameterMetaData care conţine descrierea parametrilor IN sau OUT folosiţi de
PreparedStatement.
Interfaţa ResultSetMetaData
Metadatele unui ResultSet reprezintă informaţiile despre rezultatul conţinut în
acel obiect cum ar fi numărul coloanelor, tipul şi denumirile lor, etc. Acestea sunt
obţinute apelând metoda getMetaData pentru ResultSet-ul respectiv, care va returna un
obiect de tip ResultSetMetaData ce poate fi apoi folosit pentru extragerea informaţiilor
dorite.
4. Java-protocol bază de date: Acest tip de drivere sunt drivere Java pure care
implementează un protocol de bază de date(ex. Oracle SQL Net) pentru a
comunica direct cu baza de date. De aceea, aceste drivere sunt cele mai rapide. Ca
şi driverele de tip 3, ele nu necesită biblioteci de bază de date native şi pot fi
folosite distribuit fără instalarea clientului. Driverele de tip 4 sunt specifice unui
singur DBMS.
Codul Java folosit în aplicaţii rămâne valid după tranzacţia spre alt sistem de
gestiune a bazelor de date, deoarece orice driver de orice tip respectă API-ul JDBC,
singurul pas necesar tranzacţiei fiind schimbarea driverului.
Tipurile de date din SQL sunt diferite de tipurile de date suportate de limbajul
Java. De asemenea, există deosebiri semnificative între tipurile suportate de diferite
DBMS-uri existente pe piaţă. Pentru a evita incompatibilităţile, JDBC defineşte o serie de
tipuri generice SQL prin intermediul clasei java.sql.Types, ceea ce permite
programatorului să nu fie interesat de numele tipurilor de date folosite de DBMS-ul la
care se conectează, această sarcină revenind driverului. Programatorul interacţionează
doar cu tipurile JDBC, fiind definită o mapare standard între tipurile JDBC şi tipurile
Java. Tabelul de mai jos prezintă maparea JDBC-Java:
O dată ce s-a încărcat un driver, putem să-l folosim pentru stabilirea unei
conexiuni către baza de date. O conexiune JDBC este identificată printr-un URL JDBC
specific. Sintaxa standard pentru URL-ul unei baze de date este:
jdbc:<subprotocol>:<nume>
Prima parte precizează că pentru stabilirea conexiunii se foloseşte JDBC. Partea
de mijloc <subprotocol > este un nume de driver valid sau al altei soluţii de conexiune a
bazelor de date. Ultima parte, <nume>, este un nume logic sau alias care corespunde
bazei de date fizice. Dacă baza de date va fi accesată prin Internet, secţiunea , <nume>,
va respecta următoarea convenţie de nume:
//numegazda : port/subsubnume
În acest sens, o adresă corectă este următoarea:
jdbc:mysql://localhost:386/arhiva
Prezentăm în continuare sintaxa particulară pentru câteva drivere JDBC:
ODBC-jdbc:odbc:<sursa_date>[;<nume_atribut>=<valoare_atribut>]
MySQL- jdbc:mysql://server[:port]/numeBazaDate
Oracle- jdbc:oracle:thin:@server:port:numeInstanta
JDBC 2.0 permite trimiterea spre execuţie a mai multor instrucţiuni SQL grupate
(batch) împreună, această facilitate mărind uneori performanţele. Prezentăm în
continuare un astfel de caz:
Statement inter = con.createStatement();
con.setAutoCommit(false);
inter.addBatch(”INSERT INTO archive VALUES’(1,’Popescu’,’Ioan’)”);
inter.addBatch(”INSERT INTO cantitati VALUES’(260,’file’)”);
inter.addBatch(”INSERT INTO localitati VALUES’(’iasi’,’oras’)”);
int [] actualizari = inter.executeBatch();
Dacă se doreşte realizarea de apeluri SQL având date variabile drept intrare, se va
folosi clasa PreparedStatement care moşteneşte clasa Statement. Prezentăm în
continuare modul de construcţie a unei astfel de instrucţiuni, unde con reprezintă o
instanţă Connection:
instrucţiune.setString(1,”Popescu”);
instrucţiune.setString(2,”Ion”);
instrucţiune.executeUpdate();
Această metodă de a face interogări este mai rapidă decât folosirea clasei
Statement în cazul în care dorim execuţia repetată a unei instrucţiuni SQL, deoarece
aceasta este compilată o singură dată în momentul creării instanţei clasei
PreparedStatement şi folosită apoi repetat, eventual cu valori diferite pentru parametrii.
Se poate folosi şi în cazul în care nu avem parametri, aşa cum se poate observa în
continuare:
Constantă Explicaţii
TYPE_FORWARD_ONLY Acest tip de ResultSet este cel din JDBC 1.0.
Mulţimea rezultat nu are cursor deplasabil decât
dinspre început spre sfârşit. Modificările făcute în
tabelă nu se reflectă in mulţimea rezultat .
TYPE_SCROLL_INSENSITIVE Mulţimea rezultat scrollable, deci cursorul poate fi
mutat înainte şi înapoi sau pe orice poziţie diferită de
poziţia curentă. De asemenea eventualele modificări
făcute între timp în tabelă nu sunt reflectate în
ResultSet.
TYPE_SCROLL_SENSITIVE Mulţimea rezultat scrollable. Senzitive la modificari.
Constantă Explicaţii
CONCUR_READ_ONLY ResultSet-ul nu poate fi modificat
programatic. Oferă posibilitatea unui
număr nelimitat de conectări concurente la
baza de date,deoarece nu se fac modificări
asupra tabelei care ar putea genera
conflicte. Acest tip de ResultSet este
specific driverelor conforme specificaţiei
JDBC 1.0.
CONCUR_UPDATE ResultSet-ul şi baza de date pot fi
modificate programatic. Sunt posibile un
număr limitat de conexiuni concurente dat
de tipul de concurenţă ales. Acest tip de
ResultSet este specific driverelor conforme
specificaţiei JDBC 2.0.
Statement declare =
con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
ResultSet rez = declare.executeQuerry(”select nume,prenume from archive”);
4 Procesarea rezultatelor
Pentru parcurgerea simplă a înregistrărilor unui obiect din clasa ResultSet
folosind JDBC 1.0, putem folosi metoda next(), aşa cum se poate observa în următoarea
secvenţă de cod.
În cazul JDBC 2.0, o dată obţinută mulţimea rezultat rez având cursor deplasabil,
poate fi folosită pentru a poziţiona cursorul în interiorul ResultSet-ului. Iniţial, cursorul
este poziţionat înaintea primei linii din mulţimea rezultat. În JDBC 1.0, după cum
aminteam, cursorul putea fi mutat doar înainte folosind metoda next(). Driverele care sunt
conforme cu JDBC 2.0 mai permit poziţionarea absolută a cursorului pe orice linie,
folosind metoda absolute (int nr_linie), poziţionari relative ale cursorului relativ la linia
curentă folosind relative(int nr_salt), respective deplasări înapoi folosind metoda
previos(). Dacă argumentul metodei absolute() este pozitiv, se va realize poziţionarea pe
linia corespunzătoare. Dacă argumentul este negativ, poziţionarea se va face prin
deplasare de la sfârşit la început cu un număr egal cu valoarea absolută din argument.
Astfel, absolute(1) va determina poziţionarea pe prima linie, iar absolute(-1) va determina
întotdeauna poziţionarea pe ultima linie. Pentru determinarea liniei curente, se poate
folosi metoda getRow(). De asemenea există metodele first() beforeFirst() pentru
poziţionarea pe prima, respective înainte de prima linie, last şi afterLast pentru
poziţionarea pe ultima, respective după ultima linie. Pentru testarea poziţiei, avem
metodele isFirst, is Last, isBeforeFirst(), isBeforeLast(). De remarcat că toate
poziţionările se referă la ResultSet, şi nu la baza de date interogată.
Prezentăm aceste metode folosite pentru a citi în ordinea inversă liniile din
ResultSet-ul rezultat în urma interogării precedente:
if(rez.isAfterLast()==false){
rez.afterlast();
}
while(rez.previous()){
String nume = rez.getString(2);
//nume va deșine conșinutul celulei aflată la intersecșia liniei curente din
//ResultSet cu prima coloană tot din ResultSet
String prenume = rez.getString(”prenume”);
//prenume va deșine conșinutul celulei aflată la intersecţia
//liniei curente din ResultSet cu, coloana prenume din ResultSet
System.out.println(rez.getRow()+”nume: ” + nume + ”prenume: ” +
prenume );
}
absolute(-1)//poziíonarea cursorului pe ultima linie
rez.last();
rez.deleteRow();
String sir = ” ”;
java.sql.Blob blob = rezultat.getBlob();
InputStream inn = blob.getBinaryStream();
InputStream in = new InputStreamReader(inn);
int b;
while (in.read()>-1){
b=in.read();
sir+=b;
}
in.close();
inn.close();
În ambele cazuri, şi pentru tipuri distincte, şi pentru cele structurate, returnarea se face
prin valoare, şi nu prin referinţă.
try {
//…
rs.close();
instrucţiune.close();
}
catch (SQLException e){
System.out.println(”Eroare la închidere interogare: ” + e.toString());}
finally{
try {
if ( conexiuneBazaDate != null){
conexiuneBazaDate.close();
}
}
catch (SQLException ex){
System.out.println(”Eroare la închidere conexiune: ” + ex.toString());
}
}
Aplicaţii
Se creează o bază de date denumită Studenţi în Microsoft Access. Ea conţine
tabelul Detalii ce are coloanele Nume, Prenume şi Nota. Se înregistrează aceasta ca sursă
de date (ODBC Data Source) în Administrative Tools. Numele sursei de date, care va fi
folosit şi în programul Java va fi DB.
Exemplul 1:
int nota;
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
catch(java.lang.ClassNotFoundException e) {
System.err.print("ClassNotFoundException: ");
System.err.println(e.getMessage());
try{
// get a connection
Connection con =
DriverManager.getConnection ("jdbc:odbc:DB");
prenume = rs.getString("Prenume");
nota = rs.getInt("Nota");
stmt.close();
con.close();
catch(SQLException e){
e.printStackTrace();
Exemplul 2: PreparedStatement
import java.sql.*;
String nume;
Integer[] note={5,10};
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
catch(java.lang.ClassNotFoundException e) {
System.err.print("ClassNotFoundException: ");
System.err.println(e.getMessage());
}
try{
Connection con =
DriverManager.getConnection ("jdbc:odbc:DB");
pstmt.setInt(1, note[i]);
ResultSet rs = pstmt.executeQuery();
System.out.println(note[i]);
while (rs.next()) {
nume = rs.getString("Nume")+"
"+rs.getString("Prenume");
System.out.println(nume);
pstmt.close();
con.close();
catch(SQLException e){
e.printStackTrace();
import java.sql.*;
Integer nota;
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
catch(java.lang.ClassNotFoundException e) {
System.err.print("ClassNotFoundException: ");
System.err.println(e.getMessage());
try{
// get a connection
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
ResultSet rs = stmt.executeQuery(query);
while (rs.previous()) {
nume = rs.getString("Nume");
prenume = rs.getString("Prenume");
nota = rs.getInt("Nota");
stmt.close();
con.close();
catch(SQLException e){
e.printStackTrace();
}
}
import java.sql.*;
int nota;
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
catch(java.lang.ClassNotFoundException e) {
System.err.print("ClassNotFoundException: ");
System.err.println(e.getMessage());
try{
// get a connection
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
ResultSet rs = stmt.executeQuery(query);
ResultSetMetaData md = rs.getMetaData();
if(rs.getConcurrency()==ResultSet.CONCUR_UPDATABLE)
System.out.println("UPDATABLE");
else
System.out.println("READ_ONLY");
System.out.println("Acestea sunt:");
for(int i=1;i<=nColumns;i++){
System.out.print(md.getColumnLabel(i)+" ");
System.out.println();
while (rs.next()) {
rs.updateInt("Nota", 7);
rs.updateRow();
for(int i=1;i<=nColumns;i++){
System.out.print(rs.getString(i)+" ");
System.out.println();
catch(SQLException e){
e.printStackTrace();
}
Observaţii:
1. http://java.sun.com/docs/books/tutorial/jdbc/basics/index.html - Exemplele de
aici se găsesc în codeExamples_3.0.zip
2. Cartea Java de la 0 la Expert
3. Cartea Java Database Programming Bible (2002)
De studiat:
Tranzacţii şi instrucţiuni grupate (eng. batch) – din documentaţia de mai sus.
De făcut:
Încercaţi realizarea unei conexiuni: