3. Conectarea la o bază de date
4. Operatii asupra unei baze de date
5. Alte operaţii cu baze de date
6. Facilităţi introduse de JDBC 2.0
Scopul aceste
lucrări este de a prezenta tehnologia JDBC pentru lucrul cu baze de date.
O bază de date reprezintă o modalitate de stocare
persistentă a informaţiilor pe un suport fizic cu posibilitate de
regăsire a acestora ulterior. Cel mai cunoscut model de baze de date este
cel relaţional în care datele sunt memorate sub formă de tabele.
Bazele de date relaţionale mai conţin pe lângă tabele
funţii şi proceduri, mecanisme de gestionare a utilizatorilor, tipuri
de date, etc.
Printre cei mai cunoscuţi producători de baze de date se
numără: Oracle, Microsoft, Sybase, IBM.
Pentru lucrul cu baze de date Sun a dezvoltat Java Database Connection
API. JDBC a fost creat astfel încât să simplifice lucrul cu baze de date
în java. JDBC este o interfaţă API (Application Programming
Interface) care permite unui programator java accesul la un SGBD (Sistem de
Gestiune a Bazelor de Date). Arhitectura JDBC este prezentată în cadrul
figurii 1.
Figura 1. Arhitectura JDBC.
Una dintre problemele care apare atunci când se lucrează cu baze de
date este reprezentată de incompatibilităţile dintre
diverşi producători. Deşi există limbaj standard (SQL –
92), totuşi utilizatorul trebuie să ştie cu ce tip de bază
de date lucrează. JDBC a fost proiectat astfel încât să fie
independent de tipul de bază de date cu care se lucrează.
Accesarea unei baze de date folosind JDBC este simplă şi
implică următorii paşi:
Folosind tehnologia JDBC pot fi structurate modele de aplicaţii
software pe două şi trei nivele.
Modelul pe două nivele implică comunicarea directă între
aplicaţia java şi baza de date. Aplicaţia utilizator trimite
direct către baza de date secvenţe de instrucţiuni SQL ce sunt
executate, iar rezultatele sunt întoarse către client. Baza de date poate
fi localizată pe acelaşi calculator cu aplicaţia client sau pe
un calculator aflat la distanţă, comunicarea realizându-se prin reţea
(în acest caz aplicaţia poate fi considerată o aplicaţie de tip
client server).
Figura 2. Arhitectura pe două nivele.
În cadrul modelului pe trei nivele comenzile sunt trimise către un
nivel de mijloc (intermediar), care va trimite comenzile către baza de
date. Baza de date procesează comenzile şi transmite rezultatele
către nivelul intermediar care mai apoi le va trimite către client.
Avantajele acestui model sunt: controlul mai bun al accesului, se
simplifică instalarea aplicaţie (la nivelul clientului nu este nevoie
să se instaleze o aplicaţie complexă ce consumă resurse, de
cele mai multe ori accesul realizându-se prin intermediul unei aplicaţii
de tip WEB), performanţe mai bune, mentenanţă mai uşoară,
felexibilitate.
Figura 3. Arhitectura pe 3 nivele.
In continuare sunt prezentaţi principalii paşi care trebuie
realizaţi pentru a realiza o conexiune la o bază de date din java.
Aplicaţiile din cadrul acestui laborator vor utiliza o bază de
date MySQL, iar driverul JDBC corespunzător poate fi descărcat de aici.
Pentru a testa aplicaţiile se recomandă instalarea
aplicaţiei UniServer 3.2 ce
conţine un server MySQL şi un server Apache.
Incarcarea driverului
Primul pas necesar pentru a putea lucra cu o bază de date este
încărcarea driverului bazei de date la care urmează să se
realizeze conexiunea. În funcţie de tipul bazei de date va trebui selectat
driverul JDBC corespunzător acesteia. În mod uzual pe site-ul oficial al
producătorilor de sisteme de baze de date se regăseşte si
driverul JDBC pentru conectarea din java la acea baza de date.
Incarcarea driverului este foarte simplă şi implică o
singură instrucţiune. Presupunând că se utilizează driverul
JDBC MySQL pentru conectarea la o bază de date MySQL atunci codul care
realizează încărcarea driverului este următorul:
Class.forName("com.mysql.jdbc.Driver");
Driverul JDBC încărcat are rolul de a converti comenzile SQL
într-un anumit protocol specific unui anumit SGBD.
Şirul de caractere dat ca argument la metoda forName
reprezintă clasa de tip driver. Acest şir îl regăsiţi de
obicei în documentaţia driverului. După încărcarea driverului se
poate realiza conexiunea la baza de date.
Realizarea conexiunii
Pentru realizarea conexiunii cel mai important parametru este URL-ul
bazei de date. URL-ul identifică
baza de date la care urmează să se realizeze conexiunea.
Exemplu:
jdbc:mysql://localhost:3306/contacts/
jdbc:odbc:people
URL-ul
conţine următoarele componente:
Următorul cod realizează conexiunea cu baza de date:
Connection con = DriverManager.getConnection(url,"login", "password");
public
class TestConectare {
public static void main(String[] args) {
try {
//incarcare driver petru baza
de date
Class.forName("com.mysql.jdbc.Driver");
//conectare la baza de date
Connection
conn = DriverManager.getConnection("jdbc:mysql://10.3.4.1/persoane?user=student&password=pas123”);
System.out.println("Conexiune la baza de date realizata.");
//inchide cnexiune la baza de date
conn.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
Pentru a putea efectua operaţii asupra unei baze de date la care
s-a realizat conexiunea se lucrează cu un obiect Statement. Acest obiect
se obţine din cadrul obiectului Connection astfel:
Statement stat =
con.createStatement();
Din acest moment obiectul ‘stat’ va fi utilizat pentru a efectua
operaţii asupra bazei de date.
Creare tabel
Se utilizează metoda executeUpade() care va primi ca parametru un
String care reprezintă o comandă SQL validă pentru crearea unui
tabel.
stat.executeUpdate(“CREATE TABLE PERS (NUME
VARCHAR(32), VARSTA INTEGER)”);
Introducere date în tabel
Pentru adăugarea de înregistrări în cadrul unui tabel se
utilizează aceiaşi metodă executeUpdate().
stat.executeUpdate(“INSERT INTO PERS VALUES(‘ADI’,
15)”);
Citirea conţinutului unui
tabel
Pentru citirea conţinutului unui tabel se utilizeză metoda
executeQuery() a clasei Statement.
ResultSet result = stat.executeQuery("SELECT
PROD,PRET FROM STOC");
Rezultatul interogării bazei de date va fi returnat într-un obiec
de tip ResultSet. Pentru a parcurge , linie cu linie, a rezultatelor
interogării se realizează utilizând metoda next() din cadrul
obiectului ResultSet.
In cadrul programului următor este prezentat exemplu care realizează
operaţiile de creare de tabel, inserare de înregistrări şi
interogare a unui tabel.
import java.sql.*;
public class JdbcTest {
public static
void main(String[] args) {
try{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection
con = DriverManager.getConnection("jdbc:odbc:db1");
Statement
stat = con.createStatement();
stat.executeUpdate("CREATE TABLE STOC (PROD VARCHAR(32), PRET
INTEGER)");
stat.executeUpdate("INSERT INTO STOC VALUES ('PROD1' ,
2500)");
stat.executeUpdate("INSERT INTO STOC VALUES ('PROD2' ,
7900)");
ResultSet
result = stat.executeQuery("SELECT PROD,PRET FROM STOC");
while(result.next()){
String
prod = result.getString(1);
int pret
= result.getInt(2);
System.out.println("Produs =
"+prod+" "+"Pret =
"+pret);
}
}
catch(Exception e){e.printStackTrace();}
}
}
Utilizarea clasei
PreparedStatement
Clasa PreparedStatement extinde clasa Statement. Spre deosebire de
Statement, un obiect PreparedStatemtn primeşte o comandă SQL în
momentul în care este creat. Un obiect PreparedStatement reprezintă o
comandă SQL precompilată. Această clasă se utilizează
in momentul în care se doreşte executarea unei comenzi de mai multe ori,
intrucât cresc performanţele (viteza de execuţie) , deoarece comanda
SQL este precompilată în momentul creerii obiectului PreparedStatement.
PreparedStatement ps =
con.prepareStatement("INSERT INTO STOC VALUES(?,?)");
ps.setString(1,"PROD
3");ps.setInt(2,6000);
ps.executeUpdate();
ps.setString(1,"PROD
4");ps.setInt(2,9000);
ps.executeUpdate();
Utilizarea procedurilor stocate
Procedurile stocate reprezintă un set de comenzi SQL (comenzi de
updatare şi / sau interogare) care se vor executa împreună.
Procedurile stocate sunt suportate de majoritatea DBMS-urilor dar pot
apărea variaţii în ceea ce priveşte sintaxa.
In continuare este
prezentat modul în care se creeză o procedură stocată utlizând
JDBC.
String pstoc="CREATE PROCEDURE
DISP_TABLE"+
"AS "+
"SELECT PROD, PRET FROM STOC";
Statement st = con.createStatement();
st.executeUpdate(pstoc);
In acest moment
procedura DISP_TABLE va fi compilată şi stocată în cadrul bazei
de date, ea putând fi apelată ori de câte ori este nevoie.
Executarea unei
proceduri stocate se realizează astfel:
CallableStatement cs =
con.prepareCall("{call DISP_TABLE}");
ResultSet result = cs.executeQuery();
Deplasarea cursorului în cadrul
unui obiect ResultSet
Pachetul java.sql introdus în cadrul JDK 1.2 introduce o serie de noi
facilităţi, o parte dintre aceste facilităţi fiind
prezentate în cadrul acestei secţiuni.
Dacă în cadrul JDBC 1.0 deplasarea cursorului în cadrul unui obiect
ResultSet se putea face doar înainte, utilizând metoda next(), JDBC 2.0
oferă noi facilităţi de deplasare în cadrul ResultSet.
Liniile următoare arată modul de crearea a unui ResultSet în
cadrul căruia cursorul se poate deplasa atât înainte cât şi înapoi.
Statement st = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_READ_ONLY);
Metoda createStatement primeşte doi parametri. Primul parametru
poate lua valorile TYPE_FORWARD_ONLY
, TYPE_SCROLL_INSENSITIVE
şi TYPE_SCROLL_SENSITIVE. Cel de al doilea parametru poate lua
valorile CONCUR_READ_ONLY
şi CONCUR_UPDATABLE.
Odată
obţinut obiectul ResultSet se pot folosi următoarele metode pentru
deplasarea cursorulu : absolute(),
afterLast(), beforeFirst(), first(), next(), previous(), relative(row).
Modificarea conţinutului unui obiect ResultSet
O
nouă facilitate introdusă de JDBC 2.0 este abilitatea de a modifica
liniile din cadrul unui obiect ResultSet. O dată realizate
modificările , baza de date va putea fi reîmprospătată conform
acestor modificări.
rs.absolute(2);
rs.updateString(1,"AltProdus");
rs.updateInt(2,6700);
rs.updateRow();
Secvenţa anterioară prezintă modul în care se poate
realiza reînprospătarea unei linii în cadrul unui ResulSet. Se
observă că după ce linia a fost modificată, pentru ca
aceste modifcări să se realizeza şi în cadru bazei de date, se
apelează metoda updateRow().
Inserarea unei linii în cadrul bazei de date, utilizând JDBC 1.0 se
realiza astfel:
stat.executeUpdate(”INSERT INTO STOC
VALUES(”PRODX”,9800)”)
Aceiaşi operaţie se poate realiza utlizând JDBC 2.0 astfel:
rs.moveToInsertRow();
rs.updateString("PROD", "PRODX");
rs.updateInt(2, 9800);
rs.insertRow();
Pentru a modifica o înregistrare se pot folosi atât numele coloanelor
cât şi numărul acestora. Numărul coloanei din cadrul ResultSet
nu are nici o legătură cu numărul coloanei din cadrul bazei de
date.
In momentul în care se execută moveToInsertRow(), obiectul
ResultSet memorează linia pe care se afală cursorul, după care
adaugă o nouă linie şi mută cursorul pe linia
respectivă. In aceste condiţii după ce s-a adăugat o linie
, execuţia metodei moveToCurrentRow(), determină mutarea cursorului
pe linia la care se afla înainte de inserarea noii linii.
Stergerea unei linii se realizează astfel:
rs.absolute(4);
rs.deleteRow();
Pentru a vedea cea mai recentă valoare a unei linii din cadrul
bazei de date, se utilizează metoda refreshRow().
import java.sql.*;
public class DBWork{
public static
void main(String[] args) {
try{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection con = DriverManager.getConnection("jdbc:odbc:db1");
Statement
stat = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
ResultSet
rs = stat.executeQuery("SELECT * FROM STOC");
//modificarea liniei 2 din cadrul rs
rs.absolute(2);
rs.updateString(1,"AltProdus");
rs.updateInt(2,6700);
rs.updateRow();
//adauga
linie
rs.moveToInsertRow();
rs.updateString(1, "PRODX");
rs.updateInt(2, 9800);
rs.insertRow();
//sterge
linie
rs.absolute(4);
rs.deleteRow();
rs.afterLast();
while(rs.previous()){
System.out.println(rs.getString(1)+" "+rs.getInt(2));
}
rs.close();
}
catch(Exception e){e.printStackTrace();}
}
}
Importaţi în
mediul Eclipse proiectul ce exemplifică noţiunile prezentate în acest
laborator (link proiect).
Pachetul lab.scd.db.jdbc10 conţine clase ce exemplifică operaţiile principale ce pot fi realizate asupra unei baze de date folosind clasele JDBC API.
Pachetul lab.scd.db.jdbc20 conţine clasele ce exemplifică functionalitatile adaugate in JDBC 2.0 API pentru lucrul cu baze de date.
Pachetul lab.scd.db.tableview demonstrează modul în care se poate construi o aplicaţie ce afiseaza intr-un tabel grafic continutul unui tabel din cadrul unei baze de date.
Pachetul lab.scd.db.movecursor demonstrează modul în care se poate
construi o aplicaţie ce permite parcurgerea înregistrărilor dintr-un tabel,
modificarea acestora si adăugarea de noi înregistrări. Aplicaţia
conţine de asemenea o interfaţă grafica.