Baze de date (JDBC)

Baze de date (JDBC) 1

1. Scopul lucrării 1

2. Consideraţii teoretice. 1

3. Conectarea la o bază de date. 3

4. Operatii asupra unei baze de date. 5

5. Alte operaţii cu baze de date. 6

6. Facilităţi introduse de JDBC 2.0. 7

Exerciţii 9

 

1. Scopul lucrării

 

Scopul aceste lucrări este de a prezenta tehnologia JDBC pentru lucrul cu baze de date.

           

2. Consideraţii teoretice

           

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:

  1. Obţinerea unui obiect de tip Connection ce încapsulează conexiunea la baza de date (în acest pas se realizează deci conexiunea la baza de date).
  2. Obţinerea unui obiect Statement dintr-un obiect de tip Connection. Acest obiect este folosit pentru a transmite spre execuţie comenzi SQL către baza de date. Prin intermediul acestui obiect sunt efectuate operaţii de interogare şi modificare a bazei de date.
  3. Obţinerea unui obiect ResultSet dintr-un obiect Statement. Obiectul ResultSet încapsuleaz rezultatele operaţiilor de interogare.
  4. Procesarea rezultatelor încapsulate în obiectul ResultSet.

 

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.

 

3. Conectarea la o bază de date

 

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:

  1. Componenta care specifică utilizarea driverului jdbc.
  2. Componenta care specifică mecanismul de conectare la baza de date.
  3. Identificatorul bazei de date. Acesta reprezintă un identificator – un nume logic – care este mapat de către softul de administrare al bazei de date la baza de date fizică.

 

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();

            }

   }

}          

 

4. Operatii asupra unei baze de date

 

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();}

 

  }

}          

 

                       

5. Alte operaţii cu baze de date

 

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();

 

 

6. Facilităţi introduse de JDBC 2.0

 

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();}

 

  }

}

 

Exerciţii

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.