Interfaccia Statement in JDBC
L'interfaccia Statement
di JDBC è utilizzata per eseguire istruzioni SQL semplici su un database, come query SELECT
, INSERT
, UPDATE
, e DELETE
. Appartiene al pacchetto java.sql
e fornisce metodi per interagire con il database in modo sincrono.
Statement
viene creato tramite un oggettoConnection
.- Viene utilizzato per eseguire query SQL statiche, dove non ci sono parametri variabili all'interno dell'istruzione SQL.
- Fornisce metodi per:
- Eseguire query (metodi
executeQuery
,executeUpdate
,execute
) - Gestire il risultato delle query (
ResultSet
)
- Eseguire query (metodi
-
executeQuery(String sql): Esegue un'istruzione
SELECT
e restituisce unResultSet
con i dati ottenuti.ResultSet rs = statement.executeQuery("SELECT * FROM libri");
-
executeUpdate(String sql): Esegue un'istruzione di aggiornamento (come
INSERT
,UPDATE
oDELETE
) e restituisce un intero che indica il numero di righe affette dall'operazione.int rowsAffected = statement.executeUpdate("INSERT INTO libri (titolo, pagine) VALUES ('Nuovo Libro', 100)");
-
execute(String sql): Esegue un'istruzione SQL generica. Restituisce
true
se è stato generato unResultSet
,false
in caso contrario.boolean isResultSet = statement.execute("DELETE FROM libri WHERE id = 1");
-
close(): Chiude l'oggetto
Statement
e libera le risorse.statement.close();
Ecco un esempio che mostra come creare un Statement
, eseguire una query, e gestire i risultati:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class StatementExample {
private static final String URL = "jdbc:mysql://localhost:3306/nomeDB";
private static final String USER = "username";
private static final String PASS = "password";
public static void main(String[] args) {
try (Connection con = DriverManager.getConnection(URL, USER, PASS);
Statement stmt = con.createStatement()) {
// Esecuzione di una query SELECT
ResultSet rs = stmt.executeQuery("SELECT * FROM libri");
// Lettura dei dati dal ResultSet
while (rs.next()) {
int id = rs.getInt("id");
String titolo = rs.getString("titolo");
int pagine = rs.getInt("pagine");
System.out.println("ID: " + id + ", Titolo: " + titolo + ", Pagine: " + pagine);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
Vantaggi:
- Semplicità: facile da usare per istruzioni SQL statiche e semplici.
- Ideale per operazioni singole e senza parametri variabili.
Limitazioni:
- Vulnerabilità SQL Injection: con query dinamiche, dove i dati dell'utente sono inseriti direttamente nell'SQL.
- Non ottimizzato per query ripetitive con valori variabili (per cui è preferibile
PreparedStatement
).
L'interfaccia Statement
è ideale per istruzioni SQL semplici, ma per query parametriche o operazioni più complesse è preferibile utilizzare PreparedStatement
.
PreparedStatement
è un'interfaccia JDBC che estende Statement
, progettata per eseguire query SQL parametrizzate in modo più sicuro ed efficiente. A differenza di Statement
, consente di inserire parametri variabili (attraverso segnaposti ?
), prevenendo SQL Injection e ottimizzando l'esecuzione di query ripetitive.
- Parametri: utilizza segnaposti
?
per i parametri, che vengono successivamente valorizzati tramite metodi specifici. - Sicurezza: aiuta a prevenire attacchi di SQL Injection poiché i parametri vengono trattati come dati e non come parte del codice SQL.
- Ottimizzazione: ideale per query ripetitive, poiché il DBMS può ottimizzare l’esecuzione della query grazie alla sua pre-compilazione.
-
setInt(int parameterIndex, int value), setString(int parameterIndex, String value), ecc.: impostano i valori per i segnaposti
?
in base al tipo di dato.preparedStatement.setInt(1, 10); // Imposta il primo parametro come un intero preparedStatement.setString(2, "test"); // Imposta il secondo parametro come stringa
-
executeQuery(): esegue una query
SELECT
e restituisce unResultSet
.ResultSet rs = preparedStatement.executeQuery();
-
executeUpdate(): esegue un'istruzione
INSERT
,UPDATE
oDELETE
, restituendo il numero di righe interessate.int rowsAffected = preparedStatement.executeUpdate();
-
close(): chiude il
PreparedStatement
e libera le risorse.preparedStatement.close();
Vediamo un esempio di come utilizzare PreparedStatement
per una query parametrizzata:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class PreparedStatementExample {
private static final String URL = "jdbc:mysql://localhost:3306/nomeDB";
private static final String USER = "username";
private static final String PASS = "password";
public static void main(String[] args) {
String query = "SELECT * FROM libri WHERE pagine > ? AND prezzo < ?";
try (Connection con = DriverManager.getConnection(URL, USER, PASS);
PreparedStatement pstmt = con.prepareStatement(query)) {
// Imposta i parametri della query
pstmt.setInt(1, 100); // Numero di pagine
pstmt.setDouble(2, 20.00); // Prezzo massimo
// Esecuzione della query e lettura dei risultati
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
int id = rs.getInt("id");
String titolo = rs.getString("titolo");
int pagine = rs.getInt("pagine");
double prezzo = rs.getDouble("prezzo");
System.out.println("ID: " + id + ", Titolo: " + titolo + ", Pagine: " + pagine + ", Prezzo: " + prezzo);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
Vantaggi:
- Prevenzione SQL Injection: separa i dati dal codice SQL.
- Performance ottimizzata: l’istruzione SQL viene pre-compilata dal database, rendendo le esecuzioni successive più rapide.
- Riusabilità: ideale per query ripetitive con parametri variabili.
Limitazioni:
- Solo query statiche:
PreparedStatement
non può essere utilizzato per query dinamiche in cui cambiano le colonne o le condizioni SQL in fase di esecuzione. Per queste esigenze, occorre utilizzareStatement
o comporre dinamicamente la query prima di utilizzarePreparedStatement
.
PreparedStatement
è la scelta preferibile per query sicure, parametrizzate e ripetitive, in particolare quando si gestiscono dati forniti dall'utente.
CallableStatement
è un'interfaccia JDBC usata per eseguire stored procedure nel database, ovvero funzioni o procedure predefinite e salvate lato server. A differenza di Statement
e PreparedStatement
, che sono utilizzati per inviare comandi SQL diretti, CallableStatement
permette di interagire con procedure memorizzate, consentendo operazioni più complesse e ottimizzate lato database.
- Esecuzione di stored procedure:
CallableStatement
è progettato specificamente per chiamare procedure memorizzate nel database. - Supporto di parametri IN, OUT e INOUT: può gestire parametri di input (
IN
), di output (OUT
) e misti (INOUT
). - Riusabilità e ottimizzazione: l’utilizzo di stored procedure rende le operazioni ripetitive e complesse più efficienti e consente di riutilizzare la logica direttamente dal database.
La sintassi per creare un CallableStatement
varia a seconda dei parametri:
{call nome_procedura(?, ?, ...)}
-
registerOutParameter(int parameterIndex, int sqlType): registra un parametro
OUT
specificando il tipo di dato SQL.callableStatement.registerOutParameter(2, java.sql.Types.INTEGER); // Parametro OUT di tipo INTEGER
-
setXXX(int parameterIndex, XXX value): imposta i valori dei parametri
IN
usando metodi comesetInt
,setString
, ecc.callableStatement.setInt(1, 10); // Parametro IN di tipo INTEGER
-
getXXX(int parameterIndex): recupera i valori dei parametri
OUT
dopo l’esecuzione.int result = callableStatement.getInt(2); // Recupera il valore OUT
-
execute(): esegue la stored procedure. Restituisce
true
se è stato generato unResultSet
,false
altrimenti.
Consideriamo una stored procedure nel database chiamata getLibriPerPrezzo
, che accetta un parametro IN
(prezzo massimo) e restituisce un parametro OUT
(numero di libri trovati).
DELIMITER //
CREATE PROCEDURE getLibriPerPrezzo(IN maxPrezzo DECIMAL(10, 2), OUT numeroLibri INT)
BEGIN
SELECT COUNT(*) INTO numeroLibri FROM libri WHERE prezzo <= maxPrezzo;
END //
DELIMITER ;
Ecco come usare CallableStatement
per chiamare questa procedura:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.CallableStatement;
import java.sql.SQLException;
import java.sql.Types;
public class CallableStatementExample {
private static final String URL = "jdbc:mysql://localhost:3306/nomeDB";
private static final String USER = "username";
private static final String PASS = "password";
public static void main(String[] args) {
try (Connection con = DriverManager.getConnection(URL, USER, PASS);
CallableStatement cstmt = con.prepareCall("{call getLibriPerPrezzo(?, ?)}")) {
// Imposta il parametro IN
cstmt.setDouble(1, 20.00); // prezzo massimo
// Registra il parametro OUT
cstmt.registerOutParameter(2, Types.INTEGER);
// Esegue la stored procedure
cstmt.execute();
// Recupera il parametro OUT
int numeroLibri = cstmt.getInt(2);
System.out.println("Numero di libri con prezzo <= 20.00: " + numeroLibri);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
Vantaggi:
- Riuso di codice lato server: permette di eseguire procedure memorizzate, evitando di ripetere la logica lato applicativo.
- Efficienza: le stored procedure possono essere più efficienti, specie per operazioni complesse e transazionali.
- Gestione dei parametri OUT: consente di ottenere risultati direttamente come parametri di output.
Limitazioni:
- Dipendenza dal DBMS: l’utilizzo di stored procedure può rendere l'applicazione meno portabile tra diversi database.
- Sintassi specifica: la sintassi per
CallableStatement
può variare a seconda del database.
CallableStatement
è ideale per chiamare stored procedure, offrendo un’interfaccia flessibile per operazioni complesse ed efficienti gestite lato database.