Laboratorio di reti II: Gestione di database lato server
Stefano Brocchi
[email protected]
23 marzo, 2009
Stefano Brocchi
Laboratorio di reti II: Database
23 marzo, 2009
1 / 32
Uso di database lato server
Uso di database lato server
Per la gestione di dati persistenti lato server vengono solitamente
utilizzati database
Questo offre diversi vantaggi:
Operazioni sui dati altamente ottimizzate grazie a meccanismi
ampiamente studiati e collaudati
Disponibilità di un formato standard per i dati salvati e per la loro
manipolazione
Gestione automatica della concorrenza per le richieste più semplici
Stefano Brocchi
Laboratorio di reti II: Database
23 marzo, 2009
2 / 32
Uso di database lato server
MySql
Come esempio di database con cui interfacciarsi vedremo MySql
MySql è uno dei più utilizzati database in rete. E’ distribuito
gratuitamente nella sua versione base a www.mysql.com
Le differenze di utilizzo con altri database sono comunque minime, e
comprendono solitamente solo una diversa configurazione dei driver ed
un’altra stringa di richiesta per la connessione
Stefano Brocchi
Laboratorio di reti II: Database
23 marzo, 2009
3 / 32
Uso di database lato server
Database e paradigma client-server
Il database serve richieste tramite il paradigma client-server
Quando viene avviato, un server resta in ascolto per richieste al
database
Per MySql la porta di ascolto di default è 3306
Per eseguire una query quindi sarà necessario aprire una connessione
tramite la quale inviare la richiesta e ricevere la risposta
Grazie a questa tecnica, la località di un database (in locale o in
remoto) è del tutto trasparente
Stefano Brocchi
Laboratorio di reti II: Database
23 marzo, 2009
4 / 32
PEAR e gestione di database in PHP
PEAR e il pacchetto MDB2
PEAR (PHP Extension and Application Repository) è un insieme di
pacchetti e di estensioni per PHP messi a disposizione gratuitamente
online (http://pear.php.net)
Uno dei pacchetti più utilizzati è MDB2 che consente l’interazione con
i database
Per comunicare con il DB è necessario inoltre installare l’estensione
PHP con il driver relativo al database utilizzato
Per MySql esistono principalmente due estenzioni: un driver MySql ed
un driver MySqli che supporta anche le funzionalità più avanzate
Stefano Brocchi
Laboratorio di reti II: Database
23 marzo, 2009
5 / 32
PEAR e gestione di database in PHP
Connessione al database
Connessione al database
Per eseguire delle query la prima operaziome da effettuare è importare
il pacchetto e richiedere una connessione con la seguente sintassi
<?php
require_once("MDB2.php");
$con = & MDB2::connect("mysqli://user:password@".
"host/myDatabase");
?>
Ai valori user, password, host e myDatabase vanno chiaramente
sostituiti valori opportuni
Il carattere ’&’ server per ottenere una referenza all’oggetto invece
che una sua copia. Questo modo di procedere è raccomandato nella
documentazione di PEAR
Stefano Brocchi
Laboratorio di reti II: Database
23 marzo, 2009
6 / 32
PEAR e gestione di database in PHP
Connessione al database
Connessione al database
Se la connessine va a buon fine, il metodo connect restituisce un
oggetto che estende MDB2 Driver Common
Il tipo dell’oggetto dipende dal tipo di database richiesto e dal driver
utilizzato. Nel caso di MySqli è MDB2 Driver mysqli
Stefano Brocchi
Laboratorio di reti II: Database
23 marzo, 2009
7 / 32
PEAR e gestione di database in PHP
Gestione degli errori per MDB2
Gestione degli errori del database
Se si verifica un errore, l’oggetto restituito è di tipo MDB2 Error. Per
la gestione degli errori, si può utilizzare il metodo MDB2::isError
che restituisce true se il suo argomento rappresenta un errore. Un
esempio:
<?php
require_once("MDB2.php");
$con = & MDB2::connect(...);
if (MDB2::isError($mdb2)) {
echo $mdb2->getMessage();
}
?>
Il solito meccanismo di gestione degli errori viene utilizzato per la
maggior parte delle richieste al DB (per esempio anche per l’invio di
query)
Stefano Brocchi
Laboratorio di reti II: Database
23 marzo, 2009
8 / 32
PEAR e gestione di database in PHP
Esecuzione di query
Esecuzione di query
Per eseguire istruzioni sql che non restituiscono un risulato (INSERT,
DELETE o UPDATE), si può utilizzare il metodo exec() di
MDB2 Driver Common
Il metodo richiede in ingresso la stringa rappresentante la
dichiarazione sql
Viene ritornato un intero con il numero di righe modificate se
l’esecuzione ha successo, o un MDB2 Error altrimenti
Come per ottenere la connesione, usare il carattere ’&’ per ottenere
una referenza all’oggetto
Un esempio:
$modifiedRows = & $con->exec("DELETE FROM myTable");
Stefano Brocchi
Laboratorio di reti II: Database
23 marzo, 2009
9 / 32
PEAR e gestione di database in PHP
Esecuzione di query
Esecuzione di query
Per eseguire SELECT, è necessario invece utilizzare il metodo
query() di MDB2 Driver Common
Di nuovo, in caso di errore, viene restituito un oggetto di tipo
MDB2 Error
In caso di successo, l’oggetto restituito rappresenta il risultato tramite
un oggetto MDB2 Result Common derivante da MDB2 Result
Un esempio:
$res = & $con->query("SELECT * FROM myTable");
Stefano Brocchi
Laboratorio di reti II: Database
23 marzo, 2009
10 / 32
PEAR e gestione di database in PHP
Gestione dei risultati
Gestione dei risultati
Un oggetto MDB2 Result Common contiene un puntatore ad una riga
dei risultati ottenuti, inizializzato alla prima riga
Tramite il metodo fetch row() viene restituita una riga del
risultato, ed il puntatore passa alla successiva
Se le righe sono state tutte scorse, fetch row restituisce null
Stefano Brocchi
Laboratorio di reti II: Database
23 marzo, 2009
11 / 32
PEAR e gestione di database in PHP
Gestione dei risultati
Gestione dei risultati
Di default fetch row() restituisce un vettore che contiene negli
indici da 0 a n - 1 il contenuto della riga
Specificando come argomento la costante intera
MDB2 FETCHMODE ASSOC si può ottenere un vettore associativo che
ha come chiavi i nomi delle colonne
Es. $row = $res->fetchRow(MDB2 FETCHMODE ASSOC);
Stefano Brocchi
Laboratorio di reti II: Database
23 marzo, 2009
12 / 32
PEAR e gestione di database in PHP
Gestione dei risultati
Gestione dei risultati
Altri metodi utili a disposizione per quanto riguarda il risultato di una
query:
numRows(), che restituisce il numero di righe contenute nel risultato
numCols(), che ritorna il numero di colonne contenute nel risultato
tableInfo(), che restituisce un vettore con il nome dei campi
restituiti da una SELECT
Stefano Brocchi
Laboratorio di reti II: Database
23 marzo, 2009
13 / 32
PEAR e gestione di database in PHP
Gestione dei risultati
Chiusura della connesione
L’ultimo passo da fare è eseguire la disconnessione da MySql
Richiamare il metodo disconnect() di MDB2 Driver Common:
$con->disconnect();
Stefano Brocchi
Laboratorio di reti II: Database
23 marzo, 2009
14 / 32
PEAR e gestione di database in PHP
Un esempio
Un esempio
Per riassumere, un esempio che stampa il contenuto di una tabella:
require_once("MDB2.php");
$con = & MDB2::connect(...);
$res = & $con->query("SELECT * FROM myTable");
echo "<table border = 1 width=’60%’>";
$row = $res->fetchRow();
while ($row != null) {
echo "<tr>";
foreach ($row as $value) {
echo "<td>".$value;
}
$row = $res->fetchRow();
}
echo "</table>";
$con->disconnect();
Stefano Brocchi
Laboratorio di reti II: Database
23 marzo, 2009
15 / 32
Java Database Connectivity
Java Database Connectivity
Java si connette a database grazie a driver JDBC (Java Database
Connectivity)
Il driver è fornito gratuitamente sul sito www.MySql.com sotto forma
di un file JAR
Dopo aver incluso il file JAR nel classpath, il driver sarà a
disposizione per eseguire richieste al database
Una volta incluso il driver, Java gestisce operazioni sql tramite il
pacchetto java.sql
Stefano Brocchi
Laboratorio di reti II: Database
23 marzo, 2009
16 / 32
Java Database Connectivity
Java Database Connectivity
Per interagire con i database, in Java si eseguono i seguenti passi:
Caricare il driver del database in memoria. Come descritto in seguito,
usare una import può dare problemi quindi è necessario ricorrere a
metodi alternativi
Richiedere una connesione al database ottenendo un oggetto
java.sql.Connection
Tramite la connessione, creare un’astrazione rappresentante una
dichiarazione SQL, rappresentata da un oggetto Statement
Eseguire tramite istanze di Statement le query desiderate, ed elaborare
i risultati rappresentati da oggetti di tipo ResultSet
Chiudere la connessione con il database e tutti gli oggetti che ne fanno
uso
Stefano Brocchi
Laboratorio di reti II: Database
23 marzo, 2009
17 / 32
Java Database Connectivity
Caricare il driver JDBC
JDBC: caricare il driver
Per quanto riguarda il driver JDBC per MySql, un’inclusione con una
import può dare problemi
E’ raccomandato che la classe venga caricata dinamicamente con la
seguente sintassi:
Class.forName("com.mysql.jdbc.Driver").newInstance();
Tale istruzione carica dinamicamente un’istanza del driver in memoria
Stefano Brocchi
Laboratorio di reti II: Database
23 marzo, 2009
18 / 32
Java Database Connectivity
Aprire una connessione al server sql
JDBC: richiedere una connessione
A questo punto è necessario richiedere una connessione al database
Utilizzare la classe java.sql.DriverManager per la gestione dei
driver JDBC
A disposizione il metodo statico getConnection:
public static Connection getConnection(String url);
La stringa url rappresenta un parametro di connessione comprensibile
al driver
Stefano Brocchi
Laboratorio di reti II: Database
23 marzo, 2009
19 / 32
Java Database Connectivity
Aprire una connessione al server sql
JDBC: richiesta di connessione
Per collegarsi ad un database MySql, la sintassi dell’url deve essere la
seguente
jdbc:mysql://host[:port]/database?user= user &password=pass
Dove ai valori host, port, database, user e pass vanno sostituiti
opportuni valori validi per la connessione al database
Un esempio di stringa per collegarsi al database nella rete interna del
dipartimento di informatica:
jdbc:mysql://192.167.124.67/laboratorio reti?
... user=studente2008&password=studente2008
Stefano Brocchi
Laboratorio di reti II: Database
23 marzo, 2009
20 / 32
Java Database Connectivity
Aprire una connessione al server sql
JDBC: classe Connection
Un’istanza della classe Connection rappresenta una connessione ad
un server Sql
Tramite il metodo createStatement è possibile ottenere un oggetto
di tipo Statement che rappresenta una dichiarazione che si può
inviare al server sql
Dopo aver terminato la comunicazione, è opportuno chiudere la
connessione tramite il metodo close()
Stefano Brocchi
Laboratorio di reti II: Database
23 marzo, 2009
21 / 32
Java Database Connectivity
Aprire una connessione al server sql
JDBC: classe Connection
Numerosi altri metodi sono present nella classe Connection
principalmente per vari utilizzi:
Gestione della concorrenza non limitata alla singola query (es. uso di
commit e rollback)
Ripetizione di query molto simili fra loro, dove cambiano solo alcuni
parametri, tramite oggetti PreparedStatement
Estrazione di messaggio inviati dal database (es. getWarnings()) o
di metadati relativi al db (es. getMetadata())
Stefano Brocchi
Laboratorio di reti II: Database
23 marzo, 2009
22 / 32
Java Database Connectivity
Creare una dichiarazione Sql
JDBC: classe Statement
Grazie alla classe Statement è possibile inviare query al database
In modo simile alle connessioni, l’oggetto va chiuso con il metodo
close() al termine dell’utilizzo
I principali metodi da utilizzare sono:
public ResultSet executeQuery(String sql)
Per eseguire delle SELECT ed ottenere un oggetto ResultSet che
rappresenta il risultato ottenuto
public int executeUpdate(String sql)
Per eseguire delle query che non ritornano risultati (INSERT, UPDATE
o DELETE). Il metodo ritorna il numero di righe modificate
Stefano Brocchi
Laboratorio di reti II: Database
23 marzo, 2009
23 / 32
Java Database Connectivity
Creare una dichiarazione Sql
JDBC: classe Statement
E’ inoltre possibile utilizzare il metodo boolean execute(String
sql) per dichiarazioni sql generiche
Il metodo restituisce true se l’esecuzione della dichiarazione ha
ottenuto dei risultati
E’ possibile recuperare quindi i risultati della query tramite il metodo
getResultSet()
Stefano Brocchi
Laboratorio di reti II: Database
23 marzo, 2009
24 / 32
Java Database Connectivity
Gestire i risultati
JDBC: classe ResultSet
La classe ResultSet restituisce un insieme di risultati ottenuti
tramite una query
Questi possono venir scorsi in modo sequenziale in quanto all’interno
dell’oggetto c’è un puntatore alla riga corrente, inizializzato ad
immediatamente prima della prima riga
Stefano Brocchi
Laboratorio di reti II: Database
23 marzo, 2009
25 / 32
Java Database Connectivity
Gestire i risultati
JDBC: classe ResultSet
Per passare alla riga successiva usare il metodo next(). Questo
restituisce false se la riga corrente era l’ultima. Un esempio che
scorre tutto il ResultSet:
ResultSet rs = myConnection.executeQuery(query);
while (rs.next()) {
// Operazioni sulla riga corrente
}
Esistono diversi altri metodi per la minipolazione del contatore, come
first(), last(), isFirst(), isLast()
Stefano Brocchi
Laboratorio di reti II: Database
23 marzo, 2009
26 / 32
Java Database Connectivity
Gestire i risultati
JDBC: classe ResultSet
Per ottenere il contenuto dei vari campi della colonna, esistono dei
metodi getXXX (int columnIndex) che restituiscono il contenuto
del campo di indice columnIndex (da 1 a n) trasformato nel tipo
Java XXX
Un esempio: getInt(1) restituisce il primo elemento della riga
trasformato in un intero
Sono disponibili inoltre metodi getXXX (String columnName) che
restituiscono il valore associato ad una determinata colonna
Un esempio: getInt("key") restituisce l’elemento relativo alla
colonna ”key” trasformato in un intero
Stefano Brocchi
Laboratorio di reti II: Database
23 marzo, 2009
27 / 32
Java Database Connectivity
Gestire i risultati
JDBC: classe ResultSet
E’ importante assicurarsi che le trasformazioni effettuate non causino
perdita di dati
Questo succederebbe, per esempio, convertendo un intero a 64 bit in
un intero a 32
In caso di dubbio, consultare la documentazione Java, per esempio
all’indirizzo
http://java.sun.com/j2se/1.3/docs/guide/
... jdbc/getstart/mapping.html
Per ottenere informazioni sul tipo di dato ritornato, come il numero di
colonne, è possibile utilizzare il metodo getMetaData(); l’oggetto
MetaData restituito contiene i metadati del risultato.
Come per Statement e Connection, un ResultSet va chiuso
tramite close() dopo l’utilizzo.
Stefano Brocchi
Laboratorio di reti II: Database
23 marzo, 2009
28 / 32
Java Database Connectivity
Un esempio
JDBC: un esempio
Per riassumere, un esempio completo per una richiesta al DB
Class.forName("com.mysql.jdbc.Driver").newInstance();
Connection conn = DriverManager.getConnection(
"jdbc:mysql://127.0.0.1/mydatabase" +
"?user=anuser&password=apassword");
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(
"SELECT nome,cognome FROM myTable");
while (rs.next()) {
System.out.println(rs.getString(1) + " " +
rs.getString(2));
}
rs.close();
stmt.close();
conn.close();
Stefano Brocchi
Laboratorio di reti II: Database
23 marzo, 2009
29 / 32
Java Database Connectivity
Un esempio
JDBC: un esempio
All’esempio precedente, reso più breve possibile per semplicità,
dovrebbero essere apportati miglioramenti sotto molti aspetti per
essere utilizzato in un’applicazione reale:
Assicurarsi che il driver per MySql venga caricato una sola volta
Aprire e chiudere le connessioni può essere una delle operazioni più
gravose di una query: quando possibile, utilizzare la stessa
connessione per più query
Gestire opportunamente le eccezioni ed assicurarsi che tutti gli oggetti
vengano chiusi anche in caso di errore
Stefano Brocchi
Laboratorio di reti II: Database
23 marzo, 2009
30 / 32
Esercizio
Esercizio
Progettare e realizzare un opportuno database per il forum
Creare una tabella per le informazioni sugli utenti, una per i thread ed
una per i post
E’ possibile sia inserire il contenuto dei post direttamente nel DB che
salvarli in file di testo, ed inserire nel database solo i nomi dei file
Stefano Brocchi
Laboratorio di reti II: Database
23 marzo, 2009
31 / 32
Esercizio
Esercizio
Utilizzare l’accesso al database nel lavoro fatto:
Controllare la validità delle informazioni di login tramite DB, sia dal
codice PHP che dalla servlet
Estrarre le informazioni sui thread e sui post effettuati dal database
Inserire nel DB informazioni a proposito di nuovi thread e post
Stefano Brocchi
Laboratorio di reti II: Database
23 marzo, 2009
32 / 32