JDBC: Database con Java. E’ necessario utilizzare il Driver JDBC scaricando ed installando il Connector del DBMS (es: MariaDB Connector, oppure MySQL Connector). Una volta che la Libreria JAR “mariadb-java-client-2.5.4.jar” risulta nelle nostre dipendenze Maven possiamo iniziare a lavorare sui DB. Per inserirla nelle Dipendenze SENZA SCARICARE NULLA, per un progetto Maven bisogna inserire nel file “pom.xml” la seguente dipendenza: <dependency> <groupId>org.mariadb.jdbc</groupId> <artifactId>mariadb-java-client</artifactId> <version>2.5.4</version> </dependency> All’interno del tags <dependencies>. Primo Passo: richiedere una connessione. La stringa di connessione si costruisce: final final final final final final String DBUrl = "localhost"; String DBPort = "3306"; String DBName = "libretto"; String DBUser = "root"; String DBPass = ""; String url = "jdbc:mysql://" + DBUrl + ":" + DBPort + "/" + DBName + "?user=" + DBUser + "&password=" + DBPass; Secondo Passo: eseguire delle istruzioni. Si crea uno Statement (istruzione) per richiedere una Query (richiesta), diciamo che lo Statement si carica della Query da eseguire, attenderà i risultati e poi ci restituirà un ResultSet in uscita. Il ResultSet è un tipo particolare in Java, è un CURSORE che punta ad una riga del risultato ed avrà metodi per scorrere il cursore e metodi per leggere i dati nel cursore. Quando si esegue una Query il ResultSet non punta alla prima riga del risultato ma bensì alla riga precedente. Mentre l’ultima posizione ammessa è quella DOPO l’ultimo record / tupla, quindi ad esempio in caso di un RS di 3 righe avrà 5 posizioni (-1, Riga1, Riga2, Riga3, +1). Riusciamo a capire se non siamo alla fine usando il metodo next() che restituisce TRUE se c’è ancora una riga altrimenti se siamo arrivati alla riga +1 restituisce falso. Terzo Passo: gestione dei dati. La gestione ed il recupero dei dati avviene con il cursore RS che va chiuso dopo l’utilizzo ResultSet rs = st.executeQuery(sql); while (rs.next()) { System.out.println(rs.getString("nome") + " - " + rs.getInt("punti")); } rs.close(); Se invece so già che il risultato è composto da una sola riga per posizionare il cursore sulla prima riga uso il metodo first() che restituisce il resultSet della prima riga (es: SELECT COUNT restituisce una sola riga contente un numero). Anche la connessione al DB va chiusa dopo l’utilizzo. Metodi Alternativi per eseguire le Query. Esistono altri metodi al posto di ExcecuteQuery, come ad esempio -ExecuteUpdate(sql) usata per INSERT, DELETE E UPDATE, restituisce il numero di righe interessate (1 se è andato bene, 0 se è andato male); -Execute(sql), più generico, serve per le query che non restituiscono un ResultSet; Metodi SICURI per eseguire una Query. Al fine di evitare una SQL Injection si usa un PreparedStatement inserendo poi gli attributi. String prepSql = "INSERT INTO voti (nome, punti) VALUES ( ?, ?);"; PreparedStatement prepStat = conn.prepareStatement(prepSql); prepStat.setString(1, "Geometria"); prepStat.setInt(2, 25); prepStat.executeUpdate(); DAO PATTERN (Data Access Object). Serve per disaccoppiare la gestione del DB dal resto dell’applicazione. E’ composto dalle classi: -Client, che è la nostra applicazione, ignora i dettagli del DB, ha bisogno solo di gestire dei dati; -DAO, (es: LibrettoDAO) che è la classe dedicata all’accesso ai dati vero e proprio, ignora il resto dell’app, conterrà tutti i metodi per interfacciarci con la tabella specifica (es: LibrettoDAO si interfaccia con la tabella “libretto”, CorsiDAO si interfaccia con la tabella “corsi”, ecc); PATTERN ORM (Object-Relational Mapping). In realtà ci sarà una sorta di ponte di comunicazione, sono i DTO (Data Transfer Object), in pratica si afferma che ogni tabella avrà un oggetto in Java che rappresenta il dato memorizzato, quindi DAO e Model si scambiano oggetti di questo tipo (di tipo DTO) quindi il DTO dovrebbe stare nel package del Model e non del DB. Ad esempio nel caso del Libretto Universitario sarà l’oggetto Voto: public class LibrettoDAO { public void creaVoto(Voto v) { } public List<Voto> readAllVoto() { } public Voto readFromNome(String _nome) { } } La classe DAO non avrà stati (cioè attributi, campi), non avrà dati da memorizzare, metterà a disposizione solo metodi CRUD ed eventualmente metodi di ricerca. È conveniente anche creare una classe con un solo metodo statico che restituisce l’oggetto Connection in modo che settiamo una sola volta i parametri di connessione. Nel Modello troveremo un metodo che recupera e salva oggetti DTO che gli serviranno per interfacciarsi con il Controller che poi li visualizzerà sulla View (ad esempio nel Model avremmo un metodo readAllVoto() così come lo troviamo nella classe DAO). Il Controller non chiama il DAO, chiama il metodo sul modello che a sua volta chiama il DAO. PATTERN DAO IN PRATICA. Nella pratica si crea un PACKAGE “db” o “database” al cui interno creiamo: 1)classe DTO (Data Transfer Object) che sarà l’oggetto registrato (libro, studente, corso, ecc), con i vari costruttori, i metodi getter/setter, toString, isEqual, HashCode; 2)interfaccia che conterrà i metodi che devono necessariamente scritti (libroDAO, studenteDAO) ad esempio le operazioni CRUD; 3)classe che contiene i metodi, una classe per ogni tipologia di storage (libroDAOArray, libroDAOsql), al cui interno ci sarà la struttura dati (array, mappa) che conterrà i dati che verranno realmente gestiti dal software; public class Book { private int isbn; private String title; private String author; public Book() { } public Book(int isbn, String title, String author) { this.isbn = isbn; this.title = title; this.author = author; } // altri metodi GETTER e SETTER, ISEQUAL, HASHCODE, TOSTRING } public interface BookDAO { public public public public public List<Book> getAllBooks(); Book getBookByISBN(int _isbn); void addBook(Book _book); void delBook(int _isbn); String strAllBooks(); } public class BookDAOArray implements BookDAO { private List<Book> books; public BookDAOArray() { // test only books = new ArrayList<>(); books.add(new Book(9488715, "Elementi di Fisica 1", "AA.VV")); books.add(new Book(9477604, "Elementi di Fisica 2", "AA.VV")); books.add(new Book(9466593, "Algebra Lineare", "Merkel")); } @Override public List<Book> getAllBooks() { List<Book> result = new ArrayList(books); return result; } @Override public Book getBookByISBN(int _isbn) { for (Book book : books) { if ( book.getIsbn() == _isbn ) { return book; } } return null; } }