JDBC per la gestione dei database
- I vari metodi getXXX() relativi ai vari tipi di dati possono accettare il nome della colonna del ResultSet di cui estrarre il valore e tale valore è CASE INSENSITIVE.
- Si possono cancellare le modifiche effettuate con uno statement di update utilizzando il metodo cancelRowUpdates(). Esso però deve essere invocato prima del metodo updateRow().
- Se si esegue una commit esplicita utilizzando connection.commit() quanto l’autocommit è abilitato, si ottiene una SQLException.
- La stessa cosa avviene per il ROLLBACK ed i SAVEPOINT.
- Il metodo getConnection nella classe DriveManager prende 3 parametri: URL, USERNAME e PASSWORD.
- L’URL è nel formato: <protocol>:<subprotocol>://<server>:<port>/
- Esempio: jdbc:mysql://localhost:3306/
- Un’applicazione si può connettere ad un database in uno dei 2 seguenti modi:
- java.sql.DriverManager
- java.sql.DataSource
- RowSet ha diverse sottoclassi:
- JdbcRowSet
- CachedRowSet
- FilteredRowSet
- WebRowSet
- JoinRowSet
- RowSet è scrollabile ed updatabile di default
- Un JdbcRowSet può essere creato in diversi modi:
- Tramite il costruttore di default: JdbcRowSet jdbsrs = new JdbcRowSetImpl();
- Tramite il costruttore che prende come parametro la connessione: JdbcRowSet jdbcrs = new JdbcRowSet(conn);
- Tramite un’istanza di RowSetFactory create dalla classe RowSetProvider: JdbcRowSet jdbcrs = RowSetProvider.newFactory().createJdbcRowSet();
- Connection, Statement e ResultSet implementano tutti l’interfaccia AutoCloseable e quindi possono essere utilizzati in uno statement try-with-resources.
- La classe ResultSet fornisce il metodo getInt() per recuperare un valore intero e NON getInteger().
- I metodi get della classe ResultSet si riferiscono ad eventuali ALIAS quando sono presenti, invece che al nome del campo.
- Se, ad esempio, eseguo la query: SELECT user_id, email AS _EMAIL
- Per recuperare la colonna email devo utilizzare l’alias: rs.getString(“_EMAIL”);
- Dopo la chiamata updateRow() ci deve essere la chiamata acceptChange() per far persistere le modifiche ad un RowSet.
- Statement.executeUpdate(String) ritorna un intero che indica il numero di righe interessate dall’esecuzione di uno statement di INSERT, UPDATE o DELETE.
- java.sql.SQLException è l’unica eccezione scatenata dalle API JDBC.
- Il metodo releaseSavepoint(Savepoint) è un metodo dell’oggetto Connection e NON dell’oggetto Statement:
- Connection.releaseSavepoint(Savepoint)
- Gerarchia degli oggetti Statement:
- Statement: per l’invio di statement senza parametri, tramite il metodo create Statement()
- PreparedStatement: accetta parametri IN ed è più efficiente di Statement. Il metodo da utilizzare è preparedStatement()
- CallableStatement: da utilizzare per l’esecuzione di stored procedure e può gestire parametri IN, OUT e INOUT. Il metodo da invocare in questo caso è prepareCall()
- Esecuzione degli statement:
- executeQuery -> SELECT -> ritorna un ResultSet
- executeUpdate -> INSERT, UPDATE, DELETE -> ritorna il numero di righe interessate dallo statement
- execute() -> generico -> Ritorna più ResultSet o più contatori oppure oggetti di entrambi i tipi insieme
- Il ResultSet viene scorso tramite un cursore, invocando il metodo next() che ritorna un boolean.
- Metodi disponibili nel ResultSet per spostare il cursore:
- void beforeFirst()
- void afterFirst()
- boolean absolute(int rowNumber) o boolean relative(int rowNumber) o boolean next()
- boolean prevous()
- Per recuperare i valori di una colonna della riga corrente il ResultSet mette a disposizione dei metodi di get per ogni tipo di dato. Es: getDouble()
- Le colonne possono essere identificate in due modi:
- Tramite indice di colonna: getDouble(int colNum)
- Tramite nome della colonna: getDouble(String colName)
- Gli indici di colonna in un ResultSet partono da 1 e NON da 0
- Se si utilizza un indice di colonna che NON esiste per recuperare i dati da un ResultSet si ottiene una: SQLException: Column index out of range
- Nel caso non si conosca il numero di colonne presenti nel ResultSet lo si può ricavare tramite: o resultSet.getMetadata().getColumnCount()
- E’ possibile modificare dei valori nel database direttamente tramite il ResultSet; occorre però dichiararlo come modificabile nel create Statement in questo modo: createStatement(ResultSet.CONCUR_UPDATABLE)
- Per effettuare una modifica al ResultSet occorre eseguire l’update del tipo corretto, indicando il nome della colonna da modificare o il suo indice e poi il nuovo valore da scrivere.
- Dopo aver fatto questo, per rendere effettive le modifiche, occorre chiamare il metodo updateRow().
- Se NON viene invocato il metodo updateRow() le modifiche al ResultSet non sono salvate e vengono perse.
- Per inserire un nuovo record nel database tramite il ResultSet si deve chiamare il metodo moveToInsertRow() che posiziona il cursore nel punto giusto per l’inserimento e crea il buffer per i valori da inserire. A questo punto occorre fare i vari update delle colonne con i valori da inserire ed infine si invoca il metodo insertRow().
- Per eliminare un record si scorre il cursore del ResultSet fino al record desiderato e poi si invoca il metodo deleteRow()
- Tramite il metodo executeUpdate() è possibile eseguire anche uno statement di CREATE TABLE per creare oggetti da programma.
- Nel caso si fornisca uno statement SQL sintatticamente non corretto si ottiene una SQLSyntaxErrorException.
- L’interfaccia Connection mette a disposizione il metodo getMetaData() per recuperare le informazioni relative al db.
- Tale metodo ritorna un oggetto di tipo DatabaseMetaData
- Il metodo boolean absolute(int index) sposta il cursore alla riga indicata come parametro.
- Se il valore del parametro è positivo il cursore si posizione al valore indicato
- Se invece il valore del parametro è negativo il cursore si posizione sulla riga che sta alla fine del ResultSet meno il valore passato.
- Esempio: se il ResultSet ha 10 righe e si passa al metodo absolute il parametro -3, absolute(-3), il cursore si posiziona alla riga 7, data da 10-3.
- Se viene fornito un valore, positivo o negativo, al di fuori del range del ResultSet, il cursore si posiziona alla fine o all’inizio del ResultSet. o absolute(1) equivale a chiamare il metodo first()
- absolute(-1) equivale a chiamare il metodo last()
- Auto-commit di default è settato a true. Per disabilitarlo occorre invocare il metodo setAutoCommit(false) sull’oggetto Connection.
- I savepoints possono anche NON avere un nome esplicito. In questo caso possono essere identificati tramite l’id assegnato dal data source sottostante.
- Savepoint è un’interfaccia e NON una classe astratta.
- Se in un ResultSet ci sono 2 colonne con lo stesso nome, per recuperarne i valori NON si possono usare i nome delle colonne ma si devono utilizzare gli indici.
- Un PreparedStatement può gestire solo dei parametri di tipo IN
- Un CallableStatement può gestire parametri IN, OUT ed INOUT
- Per istanziare un oggetto Statement si fa: Statement stat = connection.createStatement();
- Per aggiungere un record ad un ResultSet occorre:
- invocare il metodo: resultSet.moveToInsertRow()
- modificare i valori da inserire con il metodo resultSet.updateString() o effettuare l’inserimento effettivo con il metodo resultSet.insertRow()
- Per fare il load di un driver JDBC 3.0 occorre fare
- Class.forName(“com.mysql.jdbc.Driver”).newInstance();
- Dalla versione 4 in poi questo statement NON è più necessario e si può fare direttamente la get della connessione in questo modo:
- Connection conn = DriverManager.getConnection(“…driver string…”, “user”,”password”);
- Quando si fa il rollback() senza specificare un Savepoint si annulla l’intera transazione e NON si torna ad esempio ad un Savepoint senza nome.
- Prima di fare la get degli elementi di un ResultSet occorre invocare il metodo next() per posizionarsi sul prossimo record da leggere.
- E’ possibile utilizzare un JdbcRowSet come un componente JavaBean
- CachedRowSet cacha gli oggetti in memoria e permette di utilizzarli anche senza essere connessi alla sorgente dati.
- WebRowSet fornisce un ResultSet in formato XML e non in formato JSON
- Il filtro in un FilteredRowSet può essere modificato anche dopo la sua creazione tramite il metodo setFilter()