Java DataBase Connectivity
Accesarea unei baze de date dintr-o aplicatie Java se realizeaza prin intermediul unui program de comanda (driver) specific unui anumit sistem de gestiune a bazelor de date. Un driver intermediaza legatura dintre aplicatii si baze de date.
Java DataBase Connectivity JDBC reprezinta un API care permite lucrul cu baze de date relationale. Prin intermediul JDBC sunt transmise comenzi SQL la un server de baze de date. Folosind JDBC, nu este necesara dezvoltarea mai multor aplicatii pentru a accesa servere de baze de date care utilizeaza sisteme diferite de gestiune a bazelor de date (Oracle, MySQL, Sybase). Este suficienta o singura aplicatie, care sa utilizeze API-ul JDBC, pentru a transmite comenzi SQL la serverul de baze de date dorit. In felul acesta este asigurata portabilitatea aplicatiei.
Driver-ul JDBC ofera acces uniform la bazele de date de tip relational. JDBC include clase si interfete, scrise in Java, care furnizeaza o interfata SQL standard pentru proiectantii de aplicatii cu baze de date. Clasele si interfetele necesare in API-ul JDBC sunt disponibile prin intermediul pachetului java.sql.
Accesarea unei baze de date din Java, via JDBC, presupune realizarea urmatorilor pasi:
• stabilirea unei conexiuni la serverul de baze de date si selectarea unei baze de date;
• transmiterea si rularea unor secvente SQL;
• preluarea si prelucrarea rezultatelor obtinute.
Pentru a putea stabili conexiuni la un server MySQL prin intermediul unei aplicatii Java este necesara instalarea si configurarea driver-ului MySQL Connector/J. Driver-ul poate fi descarcat sub forma unei arhive (.gz sau .zip) de la urmatoarea adresa http://dev.mysql.com/downloads/connector/j/. Dupa dezarhivare este copiata arhiva Java corespunzatoare driver-ului (mysql-connector-java-8.0.18.jar) in directorul de instalare J2SDK (director_instalare/jre/lib/). Apoi, trebuie adaugata calea catre arhiva Java care contine driver-ul MySQL Connector/J in variabila de sistem CLASSPATH.
CLASSPATH = C:\Program Files\Java\jdk-13\lib\mysql-connector-java-8.0.18.jar
Variabila de sistem CLASSPATH contine o lista de directoare si arhive Java, despartite prin (;), in care masina virtuala Java cauta diverse clase.
Daca calea catre arhiva Java, corespunzatoare driver-ul JDBC MySQL Connector/J, a fost adaugata cu succes, atunci driver-ul este instalat si poate fi testat. Pentru a testa instalarea este suficienta crearea unei aplicatii care sa stabileasca o conexiune la un server de baze de date de tip MySQL.
Stabilire conexiune server
O conexiune la un server de baze de date reprezinta un canal de comunicatii prin care sunt transmise cereri SQL si sunt returnate raspunsuri corespunzatoare. Stabilirea unei conexiuni dintr-o aplicatie Java presupune inregistrarea (incarcarea) unui driver si realizarea conexiunii propriu-zise prin intermediul clasei DriverManager din pachetul java.sql.
Inregistrarea unui driver care permite comunicarea intre clasele din API-ul JDBC si sursele de date se realizeaza automat, dar poate fi precizata explicit prin urmatoarea linie:
Class.forName(DriverClassName);
Pentru conectarea la un server de baze de date MySQL poate fi utilizata urmatoarea valoare pentru clasa de tip driver: com.mysql.cj.jdbc.Driver.
Driver-ul asigura metode pentru stabilirea unei conexiuni, dar necesita un tip special de adresa (URL), care utilizeaza protocolul jdbc. Pentru aceasta adresa este utilizat urmatorul format:
jdbc:sub-protocol:identificator
Campul sub-protocol desemneaza tipul de driver care este utilizat pentru stabilirea conexiunii. In exemplele din acest material, sub-protocolul are valoarea mysql. Pentru identificarea sursei de date, in functie de tipul driver-ului, poate fi precizat numele unei statii, o baza de date, un port, numele unui fisier sau numele unui director.
jdbc:mysql://data.virtualcampus.ro/sakila jdbc:mysql://data.virtualcampus.ro:3306/sakila jdbc:mysql://data.virtualcampus.ro/sakila?user=airman&password=parola
Utilizand clasa DriverManager, stabilirea efectiva a unei conexiuni la un server de baze de date necesita specificarea unui URL prin intermediul unei cereri care are urmatoarea forma:
Connection conn = DriverManager.getConnection(url, nume_utilizator, parola);
Un set de tipul nume_utilizator/parola indica un cont de utilizator activ pe serverul de baze de date, cont care detine suficiente privilegii pentru accesarea bazei de date specificate in url.
Connection conn = DriverManager.getConnection("jdbc:mysql://data.virtualcampus.ro/sakila", "airman", "parola");
package ro.virtualcampus.db; | |
import java.sql.*; | |
public class JDBCTest { | |
private static Connection conn = null; | |
private String database = null; | |
private String user = null; | |
private String password = null; | |
private String hostname = null; | |
public JDBCTest(String database, String hostname, String user, String password) { | |
this.database = database; | |
this.hostname = hostname; | |
this.user = user; | |
this.password = password; | |
} | |
public void connect() { | |
try { | |
Class.forName("com.mysql.cj.jdbc.Driver"); | |
conn = DriverManager.getConnection("jdbc:mysql://" + | |
hostname + "/" + database, user, password); | |
System.out.println("Conexiunea stabilita!"); | |
} catch (SQLException e) { | |
System.out.println("Probleme la conectare!"); | |
System.out.println(e.getMessage()); | |
} catch (Exception e) { | |
System.out.println("Probleme la incarcarea driver-ului!"); | |
System.out.println(e.getMessage()); | |
} | |
} | |
public void disconnect() { | |
try { | |
if (conn != null) | |
conn.close(); | |
System.out.println("Deconectare reusita!"); | |
} catch (SQLException e) { | |
System.out.println("Probleme la deconectare!"); | |
} | |
} | |
public static void main(String[] args) { | |
JDBCTest jdbc = new JDBCTest("sakila", "data.virtualcampus.ro", "airman", "parola"); | |
jdbc.connect(); | |
jdbc.disconnect(); | |
} | |
} |
Conexiunea stabilita! Deconectare reusita!
Rulare comenzi SQL
Dupa stabilirea unei conexiuni la serverul de baze de date si selectarea unei baze de date active este necesara crearea unei instante de tip Statement prin metoda createStatement() a clasei Connection. Instanta de tip Statement permite manipularea unor comenzi SQL.
Connection conn = DriverManager.getConnection(url); Statement stmt = conn.createStatement();
Un obiect de tip Statement este un container care permite transmiterea si rularea comenzilor SQL, si obtinerea rezultatelor corespunzatoare prin intermediul conexiunii asociate. Pe langa interfata Statement, mai pot fi utilizate doua subinterfete ale acesteia: PreparedStatement si CallableStatement.
Rularea unei comenzi SQL poate fi realizata prin trei metode:
• executeQuery(): este utilizata pentru a rula comenzi SQL care returneaza un obiect de tip ResultSet;
String sql = "SELECT actor_id, first_name, last_name, last_update FROM sakila.actor LIMIT 5"; ResultSet rs = stmt.executeQuery(sql);
String sql = "SELECT a.actor_id, a.first_name, a.last_name, a.last_update " + "FROM sakila.actor a INNER JOIN actor_info ai " + "ON a.actor_id = ai.actor_id " + "LIMIT 5"; ResultSet rs = stmt.executeQuery(sql);
• executeUpdate(): este utilizata pentru a rula comenzi SQL care permit manipularea datelor (INSERT, UPDATE, DELETE – returneaza numarul de inregistrari afectate de rularea comenzii SQL) sau modificarea structurii unui tabel din baza de date (CREATE, ALTER, DROP – returneaza valoarea 0);
String sql = "INSERT INTO sakila.actor VALUES (201, \"BRUCE\", \"STERN\", NOW())"; int affectedRows = stmt.executeUpdate(sql);
String sql = "UPDATE sakila.actor SET last_name = \"STAR\" WHERE actor_id = 201"; int affectedRows = stmt.executeUpdate(sql);
String sql = "DELETE FROM sakila.actor WHERE first_name = \"BRUCE\" LIMIT 2"; int affectedRows = stmt.executeUpdate(sql);
String sql = "DROP TABLE sakila.actor"; stmt.executeUpdate(sql);
• execute(): poate fi utilizata pentru a rula orice tip de comanda SQL.
Manipulare si prelucrare rezultate
De cele mai multe ori rularea unei comenzi SQL pe o baza de date are ca si rezultat un set de date care apar sub forma tabelara. Pentru a obtine date dintr-o baza de date pot fi rulate comenzi SQL prin intermediul metodei executeQuery(). Aceasta metoda returneaza informatia sub forma unor linii de date (inregistrari), care pot fi accesate prin intermediul unei instante de tip ResultSet.
Connection conn = DriverManager.getConnection(url); Statement stmt = conn.createStatement(); String sql = "SELECT actor_id, first_name, last_name, last_update FROM sakila.actor LIMIT 5"; ResultSet rs = stmt.executeQuery(sql);
In cazul in care dorim sa accesam lista primilor 5 actori din baza de date sakila este suficienta executarea unei comenzi SQL de tip SELECT, pentru tabelul actor.
+----------+------------+--------------+---------------------+ | actor_id | first_name | last_name | last_update | +----------+------------+--------------+---------------------+ | 1 | PENELOPE | GUINESS | 2006-02-15 04:34:33 | | 2 | NICK | WAHLBERG | 2006-02-15 04:34:33 | | 3 | ED | CHASE | 2006-02-15 04:34:33 | | 4 | JENNIFER | DAVIS | 2006-02-15 04:34:33 | | 5 | JOHNNY | LOLLOBRIGIDA | 2006-02-15 04:34:33 | +----------+------------+--------------+---------------------+ 5 rows in set
Inregistrarile dintr-un obiect de tip ResultSet pot fi parcurse cu ajutorul metodei next(). De asemenea, accesarea valorilor corespunzatoare anumitor coloane poate fi realizata prin metode de tipul get<Type>() (getString(), getInt()). Coloanele dintr-un tabel pot fi referite prin intermediul numelui sau prin intermediul pozitiei coloanei
in interiorul tabelului (prima coloana din tabel are pozitia 1).
while(rs.next()) { int actori_id = rs.getInt("actor_id"); String first_name = rs.getString("first_name"); String last_name = rs.getString("last_name"); }
Toate tabelele unei baze de date detin meta-date care descriu denumirile si tipurile de date specifice fiecarei coloane. In acest fel poate fi utilizata clasa ResultSetMetadata pentru a obtine numarul de coloane dintr-un tabel sau denumirile coloanelor.
ResultSetMetaData meta = rs.getMetaData(); for(int i = 0; i < meta.getColumnCount(); i++) System.out.print(meta.getColumnName(i + 1) + "\t");
package ro.virtualcampus.db; | |
import java.sql.*; | |
public class Actors { | |
public static void main(String[] args) { | |
Connection conn = null; | |
Statement stmt = null; | |
ResultSet rs = null; | |
ResultSetMetaData meta = null; | |
try { | |
conn = DriverManager.getConnection("jdbc:mysql://data.virtualcampus.ro:3306/sakila", | |
"airman", "parola"); | |
stmt = conn.createStatement(); | |
rs = stmt.executeQuery("SELECT * FROM actor WHERE last_name LIKE 'B%' LIMIT 10;"); | |
meta = rs.getMetaData(); | |
for (int i = 0; i < meta.getColumnCount(); i++) | |
System.out.print(meta.getColumnName(i + 1) + "\t"); | |
System.out.print("\n"); | |
while (rs.next()) { | |
for (int i = 0; i < meta.getColumnCount(); i++) | |
System.out.print(rs.getObject(i + 1) + "\t"); | |
System.out.print("\n"); | |
} | |
} catch (SQLException e) { | |
System.out.println(e.getMessage()); | |
} catch (Exception e) { | |
System.out.println(e.getMessage()); | |
} finally { | |
try { | |
if (rs != null) | |
rs.close(); | |
if (stmt != null) | |
stmt.close(); | |
if (conn != null) | |
conn.close(); | |
} catch (SQLException e) { | |
System.out.println(e.getMessage()); | |
} | |
} | |
} | |
} |
actor_id first_name last_name last_update 112 RUSSELL BACALL 2006-02-15 04:34:33.0 67 JESSICA BAILEY 2006-02-15 04:34:33.0 190 AUDREY BAILEY 2006-02-15 04:34:33.0 115 HARRISON BALE 2006-02-15 04:34:33.0 187 RENEE BALL 2006-02-15 04:34:33.0 47 JULIA BARRYMORE 2006-02-15 04:34:33.0 158 VIVIEN BASINGER 2006-02-15 04:34:33.0 124 SCARLETT BENING 2006-02-15 04:34:33.0 174 MICHAEL BENING 2006-02-15 04:34:33.0 14 VIVIEN BERGEN 2006-02-15 04:34:33.0