Sunteți pe pagina 1din 12

1

JDBC
JDBC (Java DataBase Connectivity) este o parte a Java API dedicat conectrii la baze de date. Utiliznd JDBC, putem executa instruciuni/comenzi SQL pentru orice baz de date relaional. Etapele principale ntr-o aplicaie ce folosete JDBC sunt urmtoarele: - deschiderea unei conexiuni ctre baza de date; - crearea unui "obiect instruciune" prin care transmitem instruciuni SQL ctre gestionarul bazei de date; - regsirea rezultatelor. Principalele clase i interfee se gsesc n pachetul java.sql. Dintre acestea vom prezenta doar urmtoarele interfee:
public interface Connection public interface Statement

stabilete conexiunea la baza de date; creaz un "obiect instruciune"; acesta poate interoga baza de date prin invocarea de metode specializate pentru comenzile SQL, transmind ca argument un ir de caractere ce constituie o comand SQL valid; permite regsirea rezultatelor interogrii;
public interface PreparedStatement

public interface ResultSet

permite lucrul cu instruciuni SQL cu parametri. Vom prezenta n continuare numai principalele aspecte legate de JDBC. Presupunem n continuare c cititorul este familiarizat cu forma comenzilor SQL i c baza de date este creat folosind Microsoft Access. De asemenea, presupunem pentru moment c baza de date este local.

Crearea bazei de date cu Microsoft Access


Fie Agenda numele bazei de date, n care folosim tabelul Persoane. Secvena standard de aciuni ce trebuie ntreprins este urmtoarea:
-

deschid Microsoft Access Blank Access Database merg n directorul meu File Name: Agenda Create selectez: Create Table in Design view i Tables Open introduc numele cmpurilor + tipul lor nchid Salvez sub numele: Persoane fr cheie primar Click pe Persoane: pot introduce nregistrri

2
-

nchid toate ferestrele. Pentru exemplificare, plecm de la urmtorul coninut al tabelei Persoane:

nregistrarea bazei n driver-ul ODBC


Baza de date astfel creat este ns particular i nu este recunoscut ca atare de orice sistem. De aceea trebuie folosit un "intermediar" care s permit accesarea i exploatarea ei. Un astfel de intermediar este ODBC (Open DataBase Connectivity). Baza de date trebuie conectat la o surs de baze de date ODBC, prin nregistrarea ei la driver-ul ODBC. Adresa sursei de date se precizeaz prin:
String url="jdbc:odbc:surs_date"

Presupunem c numele sursei de date este AgendaODBC. Mergem succesiv n: Control Panel Administrative Tools Data Sources (ODBC) System DSN sau UserDSN (baza de date a sistemului sau a utilizatorului) Add selectez *.mdb Data Source Name: AgendaODBC Select merg n directorul meu selectez Agenda.mdb OK OK nchid. ncrcarea driver-ului ODBC se realizeaz prin:

Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");

Conectarea la baza de date


Conectarea la baza de date se realizeaz prin crearea unui obiect de tipul
Connection (interfa care ncearc s realizeze o conexiune la baza de date asociat

sursei de date ODBC). Modalitatea tipic de conectare este urmtoarea:


try { String url="jdbc:odbc:AgendaODBC"; Connection con = DriverManager.getConnection(url,"user","parola"); } catch (SQLException e) {...}

Se observ c trebuie trimis numele utilizatorului i o parol, pentru o eventual validare a accesului la baza de date.

Executarea de instruciuni SQL


Pentru executarea de instruciuni SQL trebui mai nti creat un "obiect instruciune", adic un obiect de tipul interfeei Statement:
Statement stmt = con.createStatement(); unde createStatement este o metod a interfeei Connection. Pe baza acestui

obiect este posibil executarea de instruciuni SQL, cu primirea rezultatelor cutrii. n continuare trebuie creat un ir de caractere care s reprezinte o comand SQL valid:
String sql = "...";

Urmeaz transmiterea cererii i obinerea rezultatului interogrii folosind una dintre metodele:
public ResultSet executeQuery(String sql) throws SQLException unde sql reprezint o instruciune SQL de tip SELECT. Este ntors un obiect de tipul ResultSet care permite regsirea rezultatelor cererii; public int executeUpdate(String sql) throws SQLException unde sql reprezint o instruciune SQL de unul dintre tipurile INSERT,

UPDATE, sau DELETE. Este ntors numrul liniei (nregistrrii) afectate. Interfaa:
public interface ResultSet

permite regsirea, sub forma unui tabel, a rezultatelor cutrii la executarea unei metode executeQuery. Un obiect de acest tip menine un cursor la linia curent din tabel, iniial la prima linie a acestuia. Dintre metodele interfeei ResultSet prezentm deocamdat numai urmtoarele:
public boolean next() ntoarce true dac i numai dac mai exist linii n rs, caz n care se trece la

urmtoarea nregistrare;

4
public gettip(String s)

ntoarce coninutul cmpului cu numele s din nregistrarea curent ca o valoare de tipul tip din Java; tip poate fi String, Int etc. Observaie. Obiectele con i stmt trebuie "nchise" n final prin invocarea metodei close().

Exemplu
nregistrrile (liniile) din baza de date cu care lucrm corespund informaiilor despre o persoan i au cmpurile Nume, Prenume, Localitate i Salariu, cu semnificaii evidente. Corespunztor, scriem clasa Persoana n care constructorul iniializeaz cmpurile, iar metodele ntorc valorile lor.
import java.io.*; class Persoana implements Serializable { private String nume,prenume,localitate; private int salariu; public Persoana(String n, String p, String l, int s) { nume = n; prenume = p; localitate = l; salariu = s; } public String rNume() { return nume; } public String rPrenume() { return prenume; } public String rLocalitate() { return localitate; } public int rSalariu() { return salariu; } public String toString() { return nume + "\t" + prenume + "\t" + localitate + "\t" + salariu; } }

unde implementarea interfeei Serializable va fi util ulterior pentru transmiterea la distan a obiectelor de tipul Persoana. Asupra bazei de date vom executa doar dou operaii: selectarea tuturor nregistrrilor cu un nume i o localitate date: inserarea unei noi nregistrri:

SELECT * FROM PERSOANE WHERE NUME='...' AND LOCALITATE='...' pentru care vom folosi metoda executeQuery; INSERT INTO PERSOANE (NUME,PRENUME,LOCALITATE,SALARIU) VALUES('...','...','...','...') pentru care vom folosi metoda executeUpdate. Aceste operaii corespund metodelor cauta i adauga din clasa BD, clasa care are un cmp stmt de tipul Statement, care primete valoare prin constructor: import java.sql.*; class BD { Statement stmt; BD(Statement s) { stmt = s; } public void cauta(String nume,String loc) throws Exception { Persoana p = null;

5
String my_query = "SELECT * FROM PERSOANE WHERE NUME='" + nume + "' AND LOCALITATE='" + loc + "'"; ResultSet rs = stmt.executeQuery(my_query); while ( rs.next() ) { p = new Persoana(rs.getString("Nume"), rs.getString("Prenume"), rs.getString("Localitate"), rs.getInt("Salariu") ); System.out.println(""+p); } } public void adauga(Persoana p) throws Exception { String my_stmt = "INSERT INTO PERSOANE (NUME,PRENUME,LOCALITATE,SALARIU)" + " VALUES('" + p.rNume() + "','" + p.rPrenume() + "','" + p.rLocalitate()+"','" + p.rSalariu() + "');"; int i = stmt.executeUpdate(my_stmt); System.out.println(""+p); }

Clasa Agenda de mai jos conine numai metoda principal. Aceast metod prevede crearea unei conexiuni con la baza de date, a unui "obiect instruciune" stmt i a unui obiect bd de tipul BD. n continuare sunt citite de la intrare iruri de caractere i se ntreprind urmtoarele aciuni: - dac primul ir de caractere citit este "INSERT", mai sunt citite 3 iruri de caractere i un numr ntreg; prin invocarea metodei adauga a clasei BD este inserat o nou nregistrare n baza de date; - dac primul ir de caractere citit este "SELECT", atunci mai sunt citite dou iruri de caractere nume i loc i este invocat metoda cauta a clasei BD pentru listarea tuturor personelor cu numele nume i localitatea loc; - dac primul ir de caractere citit este "STOP", atunci programul se termin.
import java.sql.*; import java.util.*; class Agenda { public static void main(String[] args) throws Exception { String id,nume,prenume,loc; int sal; Persoana P; Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); String url = "jdbc:odbc:AgendaODBC"; Connection con = DriverManager.getConnection(url,"Vasile","Sile"); Statement stmt = con.createStatement(); BD bd = new BD(stmt); Scanner sc = new Scanner(System.in); for ( ; ; ) { System.out.println("*** Comanda noua : ***"); id = sc.next(); if (id.equals("STOP")) break; else if (id.equals("SELECT")) { nume = sc.next(); loc = sc.next(); bd.cauta(nume,loc);

6
} else if (id.equals("INSERT")) { nume = sc.next(); prenume = sc.next(); loc = sc.next(); sal = sc.nextInt(); P = new Persoana(nume,prenume,loc,sal); bd.adauga(P); } else System.out.println("Comanda incorecta"); } con.close(); stmt.close(); } }

De exemplu, dac vom introduce:


SELECT Ionescu Sibiu

va fi afiat:
Ionescu Ionescu Ionescu

Ion Vasile Dan

Sibiu Sibiu Sibiu

510 560 460

Accesarea unei baze de date aflate la distan folosind socket-uri


Deoarece se vor trimite la distan obiecte de tipul Persoana, aceasta trebuie s implementeze interfaa Serializable, lucru deja realizat. Serverul va folosi clasa Server_BD.java:
import import import import java.io.*; java.sql.*; java.util.*; java.net.*;

class Server_BD { public static void main(String[] sss) throws Exception { ServerSocket ss = new ServerSocket(7777); Socket cs; System.out.println("Serverul a pornit"); Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); String url = "jdbc:odbc:AgendaODBC"; Connection con = DriverManager.getConnection(url,"Vasile","Sile"); Statement stmt = con.createStatement(); System.out.println("S-a creat legatura la baza de date"); while (true) { cs = ss.accept(); System.out.println("Client nou"); new Conexiune(cs,stmt); } } }

class Conexiune extends Thread { Socket cs; Statement stmt; Persoana p; String id,nume,prenume,loc; int sal;

7
Vector v; DataInputStream dis; ObjectOutputStream oos; Conexiune(Socket client, Statement s) { cs = client; stmt = s; start(); } public void run() { try { dis = new DataInputStream( cs.getInputStream()); oos = new ObjectOutputStream( cs.getOutputStream()); String sql; for( ; ; ) { id = dis.readUTF(); if(id.equals("SELECT")) { v = new Vector(); nume = dis.readUTF(); loc = dis.readUTF(); sql = "SELECT * FROM PERSOANE WHERE NUME='" + nume + "' AND LOCALITATE='" + loc + "'"; System.out.println("Comanda: " + sql); ResultSet rs = stmt.executeQuery(sql); while ( rs.next() ) { p = new Persoana(rs.getString("Nume"), rs.getString("Prenume"), rs.getString("Localitate"), rs.getInt("Salariu") ); System.out.println(""+p); v.addElement(p); } oos.writeObject(v); } else { // comanda INSERT nume = dis.readUTF(); prenume = dis.readUTF(); loc = dis.readUTF(); sal = dis.readInt(); p = new Persoana(nume, prenume, loc, sal); System.out.println(p+""); sql = "INSERT INTO PERSOANE "+ "(NUME,PRENUME,LOCALITATE,SALARIU)" + " VALUES('" + p.rNume() + "','" + p.rPrenume() + "','" + p.rLocalitate() + "','" + p.rSalariu() + "');"; System.out.println("Comanda: " + sql); stmt.executeUpdate(sql); System.out.println("S-a adaugat: "+p); } } } catch(IOException e) { } catch(SQLException e) { } } }

Clienii vor folosi clasa Client_BD.java:

8
import java.io.*; import java.net.*; import java.util.*; class Client_BD { public static void main(String[] args) throws Exception { String id; Persoana P; Vector v; Socket cs = new Socket("localhost",7777); DataOutputStream dos = new DataOutputStream(cs.getOutputStream()); ObjectInputStream ois = new ObjectInputStream(cs.getInputStream()); Scanner sc = new Scanner(System.in); for ( ; ; ) { System.out.println("*** Comanda noua : ***"); id = sc.next(); if (id.equals("STOP")) break; else if (id.equals("SELECT")) { dos.writeUTF("SELECT"); dos.writeUTF(sc.next()); dos.writeUTF(sc.next()); v = (Vector) ois.readObject(); while ( !v.isEmpty() ) { P = (Persoana) v.elementAt(0); System.out.println(""+P); v.removeElementAt(0); } } else if (id.equals("INSERT")) { dos.writeUTF("INSERT"); dos.writeUTF(sc.next()); dos.writeUTF(sc.next()); dos.writeUTF(sc.next()); dos.writeInt(sc.nextInt()); } else System.out.println("Comanda incorecta"); } } }

Accesarea unei baze de date aflate la distan folosind RMI


Java ofer multiple posibiliti de a accesa o baz de date aflat la distan, printre care i mecanismul invocrii la distan (RMI). Practic, vom scrie un server de Web ce va funciona pe maina pe care se afl baza de date. Clasa Persoana se afl att pe client, ct i pe server. Tot att pe client ct i pe server se va afla interfaa I_BD:
import java.rmi.*; import java.sql.*; import java.util.*; interface I_BD extends Remote { public Vector cauta (String nume, String loc) throws Exception; public void adauga(Persoana p) throws Exception; }

9 unde metoda cauta ntoarce ntr-un vector nregistrrile de tip Persoana selectate. Clientul folosete clasa Client_BD_RMI:
import java.sql.*; import java.rmi.*; import java.util.*; class Client_BD_RMI { public static void main(String[] args) throws Exception { String id,nume,prenume,loc; int sal; Persoana P; Vector v; I_BD bd = (I_BD) Naming.lookup("rmi:///bd"); Scanner sc = new Scanner(System.in); for ( ; ; ) { System.out.println("*** Comanda noua : ***"); id = sc.next(); if (id.equals("STOP")) break; else if (id.equals("SELECT")) { nume = sc.next(); loc = sc.next(); v = bd.cauta(nume,loc); while ( !v.isEmpty() ) { P = (Persoana) v.elementAt(0); System.out.println(""+P); v.removeElementAt(0); } } else if (id.equals("INSERT")) { nume = sc.next(); prenume = sc.next(); loc = sc.next(); sal = sc.nextInt(); P = new Persoana(nume,prenume,loc,sal); bd.adauga(P); } else System.out.println("Comanda incorecta"); }

} }

Serverul folosete clasa Server_BD_RMI:


import java.sql.*; import java.util.*; import java.rmi.*; import java.rmi.server.*; class Server_BD_RMI extends UnicastRemoteObject implements I_BD { Statement stmt; Server_BD_RMI(Statement s) throws Exception { stmt=s; } public Vector cauta(String nume, String loc) throws Exception { Persoana p = null; Vector v = new Vector(); String sql = "SELECT * FROM PERSOANE WHERE NUME='" + nume + "' AND LOCALITATE='" + loc + "'"; System.out.println("Comanda: " + sql);

10
ResultSet rs = stmt.executeQuery(sql); while ( rs.next() ) { p = new Persoana(rs.getString("Nume"), rs.getString("Prenume"), rs.getString("Localitate"), rs.getInt("Salariu") ); System.out.println(""+p); v.addElement(p); } return v;

public void adauga(Persoana p) throws Exception { String sql = "INSERT INTO PERSOANE (NUME,PRENUME,LOCALITATE,SALARIU)" + " VALUES('" + p.rNume() + "','" + p.rPrenume() + "','" + p.rLocalitate()+"','" + p.rSalariu() + "');"; System.out.println("Comanda: " + sql); stmt.executeUpdate(sql); System.out.println("S-a adaugat: "+p); } public static void main(String[] args) throws Exception { Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); String url = "jdbc:odbc:AgendaODBC"; Connection con = DriverManager.getConnection(url,"Vasile","Sile"); Statement stmt = con.createStatement(); Server_BD_RMI bd = new Server_BD_RMI(stmt); Naming.rebind("rmi:///bd",bd); } }

Instruciuni SQL cu parametri


Uneori programul trimite cereri de aceleai tip, dar cu alte valori pentru unul sau mai multe cmpuri. De exemplu putem trimite cereri multiple n care doar valoarea unui cmp (unor cmpuri) difer. n aceste situaii este util, dar i eficient, folosirea unor instruciuni SQL n care apar parametri. Concret, n locul cmpului (cmpurilor) vom introduce caracterul '?', umnd ca acesta s fie nlocuit cu o valoare efectiv nainte de cererea propriu-zis. Eficiena deriv din faptul c instruciunile parametrizate sunt precompilate.
SELECT * FROM PERSOANE WHERE SALARIU>?

Pentru exemplul considerat mai sus putem forma cererea parametrizat:

urmnd ca nainte de fiecare cerere s nlocuim cmpul marcat prin '?' cu o valoare efectiv printr-o metod de setare (vezi mai jos). Gestiunea instruciunilor parametrizate este facilitat de interfaa:
public interface PreparedStatement extends Statement

11 din pachetul java.sql. Interfaa definete un obiect ce reprezint o instruciune SQL precompilat. Obiectul poate fi folosit eficient pentru a executa n mod repetat instruciunea, dar pentru seturi diferite de parametri. Descriem n continuare principalele metode ale acestei interfee.
public ResultSet executeQuery() throws SQLException este analoaga metodei cu acelai nume din interfaa Statement. public int executeUpdate() throws SQLException este analoaga metodei cu acelai nume din interfaa Statement.

Metodele de setare:

public void setTip(int i, tip t) throws SQLException seteaz parametrul cu numrul de ordine i, cu precizarea c numerotarea ncepe cu 1. Driver-ul l convertete la o valoare de tipul tipSQL i l trimite bazei de

date. Iat cteva cazuri particulare:


Tip Boolean Byte Short Int Long Float Double BigDecimal String Date Time Ref URL tip boolean byte short int long float double BigDecimal String Date Time Ref URL tipSQL BIT TINYINT SMALLINT INTEGER BIGINT FLOAT DOUBLE NUMERIC VARCHAR DATE TIME REF DATALINK

Exemplu. Relum exemplul anterior i urmrim listarea succesiv a tuturor nregistrrilor n care salariul este mai mare dect 450, 500, 550, 600.
import java.sql.*; class Agenda1 { public static void main(String[] args) throws Exception { String id,nume,prenume,loc; int sal; Persoana P; Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); String url = "jdbc:odbc:AgendaODBC"; Connection con = DriverManager.getConnection(url,"Vasile","Sile"); Persoana p; String cerere="SELECT * FROM PERSOANE WHERE SALARIU>?"; PreparedStatement pstmt = con.prepareStatement(cerere); for (int i=400; i<650; i=i+50) { pstmt.setInt(1,i); System.out.println("Persoane cu salariul > "+i); ResultSet rs = pstmt.executeQuery(); while( rs.next() ) {

12
p = new Persoana( rs.getString("Nume"), rs.getString("Prenume"), rs.getString("Localitate"), rs.getInt("Salariu") ); System.out.println(""+p); } con.close(); pstmt.close(); }

} }

Persoane cu salariul > Ionescu Ion Ionescu Vasile Vasile Vasile Ionescu Dan Persoane cu salariul > Ionescu Ion Ionescu Vasile Vasile Vasile Persoane cu salariul > Ionescu Vasile Vasile Vasile Persoane cu salariul > Vasile Vasile

Executarea programului conduce la afiarea urmtoarelor rezultate:


450 Sibiu Sibiu Cluj Sibiu 500 Sibiu Sibiu Cluj Sibiu Cluj Cluj 510 560 610 460 510 560 610 560 610 610

550 600

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