Lavorare sulle basi dati con JDBC

di il
105 risposte

105 Risposte - Pagina 4

  • Re: Lavorare sulle basi dati con JDBC

    Ho studiato la OOP molto tempo fa poi nel frattempo non ho più praticato e molte cose le ho rimosse.
    Non sono in grado di replicare quel metodo di Spring.
    Ho introdotto questa miglioria ma prima di agganciare la classe al mio progetto devo introdurre qualcosa di più corposo che gli ArrayList in quanto il vero dato che esce da una SELECT è una matrice e non un vettore. Ho scordato questo aspetto.
    import java.sql.*;
    import java.util.ArrayList;
    import java.util.Date;
    
    public class PostgreSQL {
    
        public ArrayList<String> ColonneDatabase(String... colonne_dbms) {
            ArrayList<String> cd = new ArrayList();
            for(String c : colonne_dbms){
                cd.add(c);
            }
            return cd;
        }
    
        public ArrayList<String> Query(ArrayList<String> colonne_tabella, String query, Generic<?>... parametriQuery)
                throws SQLException {
            Connection conn = connect();
            PreparedStatement ps = null;
            ResultSet rs = null;
            try {
                int i = 1;
                ps = conn.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
                for(Generic<?> parametro : parametriQuery){
                    if (parametro != null) {
                        if (parametro.getob() instanceof String) {
                            ps.setString(i++, (String) parametro.getob());
                        } else if (parametro.getob() instanceof Integer) {
                            ps.setInt(i++, (Integer) parametro.getob());
                        } else if (parametro.getob() instanceof Double) {
                            ps.setDouble(i++, (Double) parametro.getob());
                        } else if (parametro.getob() instanceof Date) {
                            java.sql.Timestamp timestamp = new java.sql.Timestamp(((Date) parametro.getob()).getTime());
                            ps.setTimestamp(i++, timestamp);
                        } else {
                            System.out.println("Tipo di parametro mancante.");
                            throw new RuntimeException();
                        }
                    }
                }
                if (query.contains("SELECT")) {
                    if (colonne_tabella != null) {
                        rs = ps.executeQuery();
                        ArrayList<String> arrayList = new ArrayList();
                        int dimArray = colonne_tabella.size();
                        while (rs.next()) {
                            for (int j=0; j<dimArray; j++){
                                arrayList.add(rs.getString(colonne_tabella.get(j)));
                            }
                        }
                        return arrayList;
                    } else {
                        System.out.println("Definisci le colonne del database che desideri leggere.");
                        throw new RuntimeException();
                    }
                } else {
                    ps.executeUpdate();
                    rs = ps.getGeneratedKeys();
                    int key = 0;
                    if (rs.next()) {
                        key = rs.getInt(1);
                    }
                    ArrayList<String> arrayList = new ArrayList();
                    arrayList.add(Integer.toString(key));
                    return arrayList;
                }
            } catch (Exception e){
                System.out.println(e.getMessage());
                System.out.println("Impossibile connettersi al database oppure eseguire la query.");
            } finally {
                try {
                    if (conn != null) {
                        conn.close();
                    }
                    if (ps != null) {
                        ps.close();
                    }
                    if (rs != null) {
                        rs.close();
                    }
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
            return null;
        }
    
    }
    
    class Generic<T> {
        T ob;
        Generic(T o) {
            ob = o;
        }
        T getob() {
            return ob;
        }
        void showType() {
            System.out.println(new MetodiApplicazione().strSum("Il tipo di T è ", ob.getClass().getName()));
        }
    }
    
  • Re: Lavorare sulle basi dati con JDBC

    giannino1995 ha scritto:


    Ho studiato la OOP molto tempo fa poi nel frattempo non ho più praticato e molte cose le ho rimosse.
    Allora devi ripassare, ristudiare! E molto in fretta e BENE.
    Perché se non riesci nemmeno a "intuire", neanche vagamente, il senso di quel RowMapper (neanche leggendo brevemente il javadoc linkato prima??), allora vuol dire che la situazione è parecchio seria, "grave". Molto.

    giannino1995 ha scritto:


    in quanto il vero dato che esce da una SELECT è una matrice e non un vettore.
    Sì a livello grezzo della query è sostanzialmente una matrice. Ma in Java lavori "ad oggetti", devi modellare le entità con classi ecc..

    Se già stavi pensando di ottenere un String[][] o un Object[][] o un List<Object[]> o altro di simile, la questione è: se dovessi generare ... che so, un Excel o un file comma separated value (csv) allora ti direi che potrebbe anche bastare.
    Per qualunque altro scopo ti assicuro che ti troverai MALE a trattare dati così "destrutturati".
  • Re: Lavorare sulle basi dati con JDBC

    giannino1995 ha scritto:


    Ho studiato la OOP molto tempo fa poi nel frattempo non ho più praticato e molte cose le ho rimosse.
    E vorresti usare la programmazione generica?

    Guarda che per un programmatore è fondamentale arrivare al risultato nel minor tempo possibile. Se non conosci bene l'argomento DEVI metterlo da parte e scrivere codice più lungo, senza vergognartene. Gli strumenti più avanzati li userai più avanti.

    Sto notando che hai la tendenza a perdere tantissimo tempo in argomenti che poco c'entrano con gli obiettivi delle esercitazioni, invece di aggirare gli ostacoli. Se farai così al lavoro ti troverai malissimo
  • Re: Lavorare sulle basi dati con JDBC

    Ho seguito tantissimi thread di @giannino qui e in altri forum e concordo con @weierstrass. Oltre al fatto che tende a comprare mille libri da mille pagine per leggerli ma poi produce poco e nulla dimenticando quel poco che ha imparato. Voler leggere e disquisire di tutto vuol dire non conoscere bene nulla. Più volte l'ho detto a @giannino ma inutilmente. E questo lunghissimo thread ne è la prova. Tra poco lascerà perdere questo argomento per passare a chissà cosa rendendo del rutto inutili gli sforzi dell'ottimo andbin.
  • Re: Lavorare sulle basi dati con JDBC

    Si avete ragione, bisogna lavorare di più sugli oggetti e sulle interfacce però mi sembra più comodo un metodo che accetta come input:
    1.Colonne della tabella da leggere;
    2.Query;
    3.Valori da sostituire ai ? per proteggersi da SQL injection.

    e che fornisce come output:
    a.La TreeMap contenente i record di proprio interesse oppure l’id della riga editata, aggiunta o cancellata.
    Non è bello come il metodo di Spring inoltre l’assenza di un'interfaccia da vita a varie interpretazioni ma essendo un codice solo per questa esercitazione forse mi conviene accontentarmi. Non vorrei rischiare di perdere troppo tempo su questo punto. Se vedo che il metodo scritto mi genera dei problemi allora ci ritorno sopra.
    Inoltre la mia applicazione senza DB funziona usando una classe OggettoUtente strutturata in questo modo:
    OggettoUtente
    
    public class OggettoUtente {
    
        private String Utente;
        private Double Latitudine;
        private Double Longitudine;
        private Date Tempo;
        private Double Velocita;
        private String[] Posizione = new String[5];
        private TreeMap<Integer, String[]> Percorso = new TreeMap<>();
        private final double minVelocity = 0;
        private final double maxVelocity = 100;
    
    }
    // Altri metodi per riempire Percorso con i vari valori inseriti dall'utente...
    
    Classe per leggere, scrivere, modificare ed aggiungere valori al DB
    
    import java.sql.*;
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.TreeMap;
    
    public class PostgreSQL {
    
        static {
            try {
                Class.forName("org.postgresql.Driver");
            } catch (ClassNotFoundException e) {
                throw new ExceptionInInitializerError(e);
            }
        }
    
        PostgreSQLCredenziali psc = new PostgreSQLCredenziali();
        private final String url = psc.getUrl();
        private final String user = psc.getUser();
        private final String password = psc.getPassword();
    
        public Connection connect() {
            Connection conn = null;
            try {
                // Si utilizza il metodo getConnection() dell'oggetto DriverManager contenuto in JDBC.
                conn = DriverManager.getConnection(url, user, password);
                // Si invia un avviso nella shell dell'IDE (operazione non necessaria).
                System.out.println("Connesso al server PostgreSQL con successo.");
            } catch (SQLException e) {
                // Si genera questa eccezione se non si riesce per qualche motivo ad eseguire una connessione al DBMS.
                System.out.println(e.getMessage());
            }
            return conn;
        }
    
        public ArrayList<String> ColonneDatabase(String... colonne_dbms) {
            ArrayList<String> cd = new ArrayList();
            for(String c : colonne_dbms){
                cd.add(c);
            }
            return cd;
        }
    
        public TreeMap<Integer, String[]> Query(
                ArrayList<String> colonne_tabella,
                String query,
                Generic<?>... parametriQuery
        ) throws SQLException {
            int dimArray;
            String[] Posizione;
            TreeMap<Integer, String[]> Percorso = new TreeMap<>();
            Connection conn = connect();
            PreparedStatement ps = null;
            ResultSet rs = null;
            try {
                int i = 1;
                ps = conn.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
                for(Generic<?> parametro : parametriQuery){
                    if (parametro != null) {
                        if (parametro.getob() instanceof String) {
                            ps.setString(i++, (String) parametro.getob());
                        } else if (parametro.getob() instanceof Integer) {
                            ps.setInt(i++, (Integer) parametro.getob());
                        } else if (parametro.getob() instanceof Double) {
                            ps.setDouble(i++, (Double) parametro.getob());
                        } else if (parametro.getob() instanceof Date) {
                            java.sql.Timestamp timestamp = new java.sql.Timestamp(((Date) parametro.getob()).getTime());
                            ps.setTimestamp(i++, timestamp);
                        } else {
                            System.out.println("Tipo di parametro mancante.");
                            throw new RuntimeException();
                        }
                    }
                }
                if (query.contains("SELECT")) {
                    dimArray = colonne_tabella.size();
                    if (dimArray>0) {
                        rs = ps.executeQuery();
                        Posizione = new String[dimArray];
                        int k = 0;
                        while (rs.next()) {
                            for (int j=0; j<dimArray; j++){
                                Posizione[j] = rs.getString(colonne_tabella.get(j));
                            }
                            Percorso.put(k,Posizione);
                            Posizione = new String[dimArray];
                            k++;
                        }
                        return Percorso;
                    } else {
                        System.out.println("Definisci le colonne del database che desideri leggere.");
                        throw new RuntimeException();
                    }
                } else {
                    ps.executeUpdate();
                    rs = ps.getGeneratedKeys();
                    int key = 0;
                    if (rs.next()) {
                        key = rs.getInt(1);
                    }
                    Posizione = new String[1];
                    Posizione[0] = Integer.toString(key);
                    Percorso.put(0,Posizione);
                    return Percorso;
                }
            } catch (Exception e){
                System.out.println(e.getMessage());
                System.out.println("Impossibile connettersi al database oppure eseguire la query.");
            } finally {
                try {
                    if (conn != null) {
                        conn.close();
                    }
                    if (ps != null) {
                        ps.close();
                    }
                    if (rs != null) {
                        rs.close();
                    }
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
            return null;
        }
    
    }
    
    class Generic<T> {
        T ob;
        Generic(T o) {
            ob = o;
        }
        T getob() {
            return ob;
        }
        void showType() {
            System.out.println(new MetodiApplicazione().strSum("Il tipo di T è ", ob.getClass().getName()));
        }
    }
    
    Esempio di utilizzo:
    
    // inizializzo la classe:
    PostgreSQL PostgreSQL = new PostgreSQL();
    // setto le colonne che voglio leggere o null se non voglio leggere nulla ma voglio scrivere:
    ArrayList<String> colonne_utenti = PostgreSQL.ColonneDatabase(
                    "id",
                    "nome",
                    "password");
    // lancio la query e recupero i dati:
    TreeMap<Integer, String[]> Percorso = PostgreSQL.Query(
                    colonne_utenti,
                    "SELECT * FROM utenti WHERE id = ? OR id = ? OR id = ?",
                    new Generic<Integer>(1),
                    new Generic<Integer>(2),
                    new Generic<Integer>(4)
    );
    // stampo i dati per vedere cosa ho combinato:
    M.stampaTreeMap(Percorso);
    
    Output:
    %%%%%%%%%% TEST %%%%%%%%%%
    Test metodo Query() della classe PostgreSQL
    Connesso al server PostgreSQL con successo.
    L'oggetto TreeMap è composto da:
    --------------------------------
    Chiave: 0 Valori: {1, Topolino, fgbdbdfb}
    Chiave: 1 Valori: {2, Pippo, bbdfbcbfg}
    Chiave: 2 Valori: {4, Paperino, fgbdb}
    --------------------------------
    P.S. (è solo una curiosità...): Ho scoperto che PostgreSQL ha un metodo chiamato RANGE. Volevo sapere se esiste anche qualcosa di simile da usare in fase di creazione di una tabella e dire che un dato valore numerico oltre ad essere un double sia anche compreso in un certo intervallo.
  • Re: Lavorare sulle basi dati con JDBC

    giannino1995 ha scritto:


    in fase di creazione di una tabella e dire che un dato valore numerico oltre ad essere un double sia anche compreso in un certo intervallo.
    Si chiamano in generale constraints ("vincoli") e in modo specifico dei check constraints

    --> www.postgresql.org/docs/current/ddl-constraints.html


    EDIT:

    giannino1995 ha scritto:


    però mi sembra più comodo un metodo che accetta come input:
    1.Colonne della tabella da leggere;
    [...]
    e che fornisce come output:

    a.La TreeMap contenente i record di proprio interesse
    Adesso a te "sembra" comodo. In realtà questo approccio ha svariati problemi. Primo fa tutti il fatto che ti costringe a restituire e poi gestire tutti i dati come String. Pensa ai valori numerici ... o peggio alle date. Sul breve termine forse fai qualcosa. Ma se fosse una applicazione "a lungo termine" sarebbe disastroso già dopo poco tempo.

    Il punto è che non hai (più) le nozioni per comprendere le assurdità che hai scritto. Quindi cerca pure di concludere questa "esercitazione" appena e il prima possibile. Ma poi riprendi lo studio di TUTTE le basi sulla OOP, se vuoi andare avanti con Java. E lo dico per completezza: un framework come Spring sarebbe off-limits per te se non hai quelle basi. Spring si basa fortemente su OOP, design pattern, IoC/dependency-injection, interfacce di astrazione, bean, bean che sono factory di altri bean, ecc... Se non hai basi solide su OOP/pattern, da Spring non ci caveresti proprio nulla ...
  • Re: Lavorare sulle basi dati con JDBC

    Che belli i vincoli! Grazie mille!
  • Re: Lavorare sulle basi dati con JDBC

    Andbin una cosa di questo tipo qui può andare bene? sono sulla strada giusta?
    Utente.java
    // La classe Utente rappresenta il record della tabella utenti del DB.
    public class Utente {
        private long id;
        private String nome;
        private String password;
    
        public long getId() {
            return id;
        }
    
        public void setId(long id) {
            this.id = id;
        }
    
        public String getNome() {
            return nome;
        }
    
        public void setNome(String nome) {
            this.nome = nome;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    }
    
    UtenteDAO.java
    import java.util.List;
    // UtenteDAO definisce i metodi che devono essere creati per interagire con la tabella utenti del DB.
    // Creo un'interfaccia perché i metodi per accedere al database sono gli stessi per ogni database ma il codice delle
    // query possono variare da DB a DB.
    public interface UtenteDAO {
        public interface ContactDAO {
            public List<Utente> findAll();
    
            public List<Utente> findByName(String name);
    
            public Utente findById(long id);
    
            public void insert(Utente u);
    
            public void delete(Utente u);
    
            public void update(Utente u);
        }
    }
    
    UtenteDAOPostgreSQL.java
    import java.sql.*;
    import java.util.ArrayList;
    import java.util.List;
    // UtenteDAOPostgreSQL definisce i metodi che devono essere creati per interagire con la tabella utenti di PostgreSQL.
    public class UtenteDAOPostgreSQL implements UtenteDAO {
    
        // PASSO 1
        // Si introducono le credenziali di accesso al DB.
        PostgreSQLCredenziali psc = new PostgreSQLCredenziali();
        private final String url = psc.getUrl();
        private final String user = psc.getUser();
        private final String password = psc.getPassword();
    
        // PASSO 2
        // Si crea una connessione al DB.
        public Connection connect() {
            Connection conn = null;
            try {
                // Si utilizza il metodo getConnection() dell'oggetto DriverManager contenuto in JDBC.
                conn = DriverManager.getConnection(url, user, password);
            } catch (SQLException e) {
                // Si genera questa eccezione se non si riesce per qualche motivo ad eseguire una connessione al DBMS.
                System.out.println(e.getMessage());
            }
            return conn;
        }
    
        // PASSO 3
        // Si implementano i metodi dell'interfaccia UtenteDAO
        public List<Utente> findAll() {
            Connection c = null;
            Statement s = null;
            ResultSet rs = null;
            //public Utente findById ( long id);
            try {
                c = connect();
                s = c.createStatement();
                rs = s.executeQuery("SELECT * FROM utenti");
                List<Utente> lista = new ArrayList<Utente>();
                // Processo rs e popolo lista
                while (rs.next()) {
                    Utente Utente = new Utente();
                    Utente.setId(rs.getInt("id"));
                    Utente.setNome(rs.getString("nome"));
                    Utente.setPassword(rs.getString("password"));
                    lista.add(Utente);
    
                }
                return lista;
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                try {
                    if (rs != null) rs.close();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
                try {
                    if (s != null) s.close();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
                try {
                    if (c != null) c.close();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        };
        // Si implementano i metodi dell'interfaccia UtenteDAO
        public List<Utente> findByName(String name) {
            return null;
        };
        // Si implementano i metodi dell'interfaccia UtenteDAO
        public Utente findById(long id) {
            return null;
        };
        // Si implementano i metodi dell'interfaccia UtenteDAO
        public void insert(Utente u) {
    
        };
        // Si implementano i metodi dell'interfaccia UtenteDAO
        public void delete(Utente u) {
    
        };
        // Si implementano i metodi dell'interfaccia UtenteDAO
        public void update(Utente u) {
    
        };
    }
    
    Main.java
    System.out.println("\n%%% TEST su UtenteDAOPostgreSQL %%%");
            UtenteDAOPostgreSQL UtenteDAOPostgreSQL = new UtenteDAOPostgreSQL();
            List<Utente> lista;
            lista = UtenteDAOPostgreSQL.findAll();
            int k = 0;
            String[] Posizione = new String[3];
            TreeMap<Integer, String[]> Utenti = new TreeMap<>();
            try {
                for(int i=0; i<lista.size(); i++){
                    Posizione[0] = String.valueOf(lista.get(i).getId());
                    Posizione[1] = lista.get(i).getNome();
                    Posizione[2] = lista.get(i).getPassword();
                    Utenti.put(k++,Posizione);
                    Posizione = new String[3];
                }
                M.stampaTreeMap(Utenti);
            } catch (Exception e){
                System.out.println("La lista di oggetti è vuota o nulla.");
            }
    Output su shell di IntelliJ
    %%% TEST su UtenteDAOPostgreSQL %%%
    L'oggetto TreeMap è composto da:
    --------------------------------
    Chiave: 0 Valori: {1, Topolino, dagg}
    Chiave: 1 Valori: {2, Pippo, sadf}
    Chiave: 2 Valori: {3, Pluto, sadfs}
    Chiave: 3 Valori: {4, Paperino, sadf}
    Chiave: 4 Valori: {6, SuperPippo, sadf}
    --------------------------------
    P.S.:Ecco il mio nuovo DB:
    CREATE TABLE utenti (
    	id SERIAL PRIMARY KEY,
    	nome VARCHAR(255) NOT NULL,
    	password VARCHAR(255) NOT NULL,
    	UNIQUE (nome)
    );
    CREATE TABLE spostamenti (
    	id SERIAL PRIMARY KEY,
    	id_utente INT NOT NULL,
    	latitudine DOUBLE PRECISION NOT NULL,
    	CHECK (latitudine >= -90.0 AND latitudine <= 90.0),
    	longitudine DOUBLE PRECISION NOT NULL,
    	CHECK (longitudine >= -180.0 AND longitudine <= 180.0),
    	tempo TIMESTAMP NOT NULL,
    	velocita DOUBLE PRECISION,
    	FOREIGN KEY (id_utente) REFERENCES utenti (id) ON DELETE CASCADE
    );
  • Re: Lavorare sulle basi dati con JDBC

    giannino1995 ha scritto:


    Andbin una cosa di questo tipo qui può andare bene? sono sulla strada giusta?
    (sì e no).

    - Utente: ok
    - UtenteDAO no. Hai messo una nested interface ContactDAO (perché??). Ma UtenteDAO è comunque una interfaccia "vuota" (non ha metodi!!). Quindi in UtenteDAOPostgreSQL un implements UtenteDAO non obbliga un bel nulla (se avessi messo gli @Override te ne accorgevi ..).
    - UtenteDAOPostgreSQL: più o meno. Il find non è gestito benissimo. Parlo in generale ma anche riguardo le eccezioni. Però il setup della lista è corretto. Evita comunque Utente Utente. Nomi così fanno solo confusione.
    - quello che hai defino "main", sì, più o meno. Potevi risparmiare il doppio new String[3] (basta uno all'inizio nel corpo del for). In ogni caso non mi è chiaro perché vuoi avere un value che è un array di 3 String eterogenee (un id, un nome, una password) ...
    - le CREATE TABLE, sì sono ok, non vedo nulla di palesemente errato.
  • Re: Lavorare sulle basi dati con JDBC

    andbin ha scritto:


    In ogni caso non mi è chiaro perché vuoi avere un value che è un array di 3 String eterogenee (un id, un nome, una password)
    Quello non guardarlo, mi serve solo per stampare in console il risultato del test e verificare che il metodo funzioni.
  • Re: Lavorare sulle basi dati con JDBC

    giannino1995 ha scritto:


    Quello non guardarlo, mi serve solo per stampare in console il risultato del test e verificare che il metodo funzioni.
    Ok. Ma verifica comunque il resto!
  • Re: Lavorare sulle basi dati con JDBC

    Ho completato UtenteDAOPostgreSQL, aggiunto closeAll(), modificato leggermente le eccezioni e corretto il codice dell'interfaccia ma non saprei proprio come impedire gli @Override dentro le interfacce.
    Main.jsp è il classico Main di java. Ho chiuso per un istante il mio progetto su Maven con la mia esercitazione ed ho creato un progetto semplice in java per testare il driver JDBC.

    Così può andare?

    Utente.java
    public class Utente {
        private long id;
        private String nome;
        private String password;
        public long getId() {
            return id;
        }
        public void setId(long id) {
            this.id = id;
        }
        public String getNome() {
            return nome;
        }
        public void setNome(String nome) {
            this.nome = nome;
        }
        public String getPassword() {
            return password;
        }
        public void setPassword(String password) {
            this.password = password;
        }
    }
    UtenteDAO.java
    import java.sql.SQLException;
    import java.util.List;
    public interface UtenteDAO {
        public List<Utente> findAll() throws SQLException;
        public Utente findByName(String nome) throws SQLException;
        public Utente findById(long id) throws SQLException;
        public long insert(Utente u) throws SQLException;
        public long delete(Utente u) throws SQLException;
        public long update(Utente u) throws SQLException;
    }
    UtenteDAOPostgreSQL.java
    import java.sql.*;
    import java.util.ArrayList;
    import java.util.List;
    
    public class UtenteDAOPostgreSQL implements UtenteDAO {
        PostgreSQLCredenziali psc = new PostgreSQLCredenziali();
        private final String url = psc.getUrl();
        private final String user = psc.getUser();
        private final String password = psc.getPassword();
        public Connection connect() {
            Connection conn = null;
            try {
                conn = DriverManager.getConnection(url, user, password);
                System.out.println("Connesso al server PostgreSQL con successo.");
            } catch (SQLException e) {
                System.out.println("Impossibile connettersi al server PostgreSQL.");
                System.out.println(e.getMessage());
            }
            return conn;
        }
        
        public void closeAll(ResultSet rs, PreparedStatement ps, Connection conn) {
            try {
                if (rs != null) rs.close();
            } catch (Exception e) {
                System.out.println("Impossibile chiudere il ResultSet.");
                throw new RuntimeException(e);
            }
            try {
                if (ps != null) ps.close();
            } catch (Exception e) {
                System.out.println("Impossibile chiudere il PreparedStatement.");
                throw new RuntimeException(e);
            }
            try {
                if (conn != null) conn.close();
            } catch (Exception e) {
                System.out.println("Impossibile chiudere la connessione.");
                throw new RuntimeException(e);
            }
        }
        
        public List<Utente> findAll() throws SQLException {
            Connection conn = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            Utente utente;
            try {
                conn = connect();
                ps = conn.prepareStatement("SELECT * FROM utenti");
                rs = ps.executeQuery();
                List<Utente> lista = new ArrayList<Utente>();
                while (rs.next()) {
                    utente = new Utente();
                    utente.setId(rs.getInt("id"));
                    utente.setNome(rs.getString("nome"));
                    utente.setPassword(rs.getString("password"));
                    lista.add(utente);
                }
                return lista;
            } catch (Exception e) {
                System.out.println("Impossibile eseguire la query.");
                System.out.println(e.getMessage());
            } finally {
                closeAll(rs, ps, conn);
            }
            return new ArrayList<Utente>();
        }
        
        public Utente findByName(String nome) throws SQLException {
            Connection conn = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            Utente utente;
            try {
                conn = connect();
                ps = conn.prepareStatement("SELECT * FROM utenti WHERE nome = ?");
                ps.setString(1, nome);
                rs = ps.executeQuery();
                List<Utente> lista = new ArrayList<Utente>();
                utente = new Utente();
                while (rs.next()) {
                    utente.setId(rs.getInt("id"));
                    utente.setNome(rs.getString("nome"));
                    utente.setPassword(rs.getString("password"));
                }
                return utente;
            } catch (Exception e) {
                System.out.println("Impossibile eseguire la query.");
                System.out.println(e.getMessage());
            } finally {
                closeAll(rs, ps, conn);
            }
            return new Utente();
        }
        
        public Utente findById(long id) throws SQLException {
            Connection conn = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            Utente utente;
            try {
                conn = connect();
                ps = conn.prepareStatement("SELECT * FROM utenti WHERE id = ?");
                ps.setLong(1, id);
                rs = ps.executeQuery();
                List<Utente> lista = new ArrayList<Utente>();
                utente = new Utente();
                while (rs.next()) {
                    utente.setId(rs.getInt("id"));
                    utente.setNome(rs.getString("nome"));
                    utente.setPassword(rs.getString("password"));
                }
                return utente;
            } catch (Exception e) {
                System.out.println("Impossibile eseguire la query.");
                System.out.println(e.getMessage());
            } finally {
                closeAll(rs, ps, conn);
            }
            return new Utente();
        }
        
        public long insert(Utente u) throws SQLException {
            Connection conn = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            long riga = 0;
            try {
                conn = connect();
                String query = "INSERT INTO utenti (nome, password) VALUES (? , ?)";
                ps = conn.prepareStatement(query, PreparedStatement.RETURN_GENERATED_KEYS);
                ps.setString(1, u.getNome());
                ps.setString(2, u.getPassword());
                ps.executeUpdate();
                rs = ps.getGeneratedKeys();
                if (rs.next()) {
                    riga = rs.getLong(1);
                }
                return riga;
            } catch (Exception e) {
                System.out.println("Impossibile eseguire la query.");
                System.out.println(e.getMessage());
            } finally {
                closeAll(rs, ps, conn);
            }
            return 0;
        }
        
        public long delete(Utente u) throws SQLException {
            Connection conn = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            long riga = 0;
            try {
                conn = connect();
                String query = "DELETE FROM utenti WHERE nome = ?";
                ps = conn.prepareStatement(query, PreparedStatement.RETURN_GENERATED_KEYS);
                ps.setString(1, u.getNome());
                ps.executeUpdate();
                rs = ps.getGeneratedKeys();
                if (rs.next()) {
                    riga = rs.getLong(1);
                }
                return riga;
            } catch (Exception e) {
                System.out.println("Impossibile eseguire la query.");
                System.out.println(e.getMessage());
            } finally {
                closeAll(rs, ps, conn);
            }
            return 0;
        }
        
        public long update(Utente u) throws SQLException {
            Connection conn = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            long riga = 0;
            try {
                conn = connect();
                String query = "UPDATE utenti SET nome = ?, password = ? WHERE nome = ?";
                ps = conn.prepareStatement(query, PreparedStatement.RETURN_GENERATED_KEYS);
                ps.setString(1, u.getNome());
                ps.setString(2, u.getPassword());
                ps.setString(3, u.getNome());
                ps.executeUpdate();
                rs = ps.getGeneratedKeys();
                if (rs.next()) {
                    riga = rs.getLong(1);
                }
                return riga;
            } catch (Exception e) {
                System.out.println("Impossibile eseguire la query.");
                System.out.println(e.getMessage());
            } finally {
                closeAll(rs, ps, conn);
            }
            return 0;
        }
    }
    
    Main.jsp
    ... il solito ... codice scritto solo per testare ...
  • Re: Lavorare sulle basi dati con JDBC

    giannino1995 ha scritto:


    aggiunto closeAll()
    Un "closeAll" del genere tra l'altro non l'ho mai visto fare così. Non servirebbe (se le eccezioni fossero trattate diversamente) e comunque non è lo stesso corretto al 100% (vedi sotto tra poco).

    giannino1995 ha scritto:


    ma non saprei proprio come impedire gli @Override dentro le interfacce.
    Ho quasi "paura" a chiedertelo: sai a cosa serve l'annotation @Override ?

    giannino1995 ha scritto:


    Così può andare?
    - Utente sì, ok (lo era già prima).

    - UtenteDAOPostgreSQL: continui a fare molte confusioni sulle eccezioni.

    Partiamo dal connect(). Fai un catch di SQLException, che potrebbe anche aver senso. Ma se c'è SQLException, tu alla fine fai restituire null. Il punto è che nei metodi sotto usi subito conn, senza fare alcun test.

    conn = connect();
    ps = conn.prepareStatement("SELECT * FROM utenti");

    E lì sbucherebbe fuori un NullPointerException. Che denota un TUO baco nel codice. Quindi sarebbe meglio se SQLException uscisse da connect(), invece di "zittirla" facendo restituire null.

    Poi comunque vedo che fai solo dei System.out.println in caso di errore. In una applicazione "console" è abbastanza chiaro dove va il System.out. In una web application NON è così scontato dove va a finire l'output su System.out. Dipende da vari fattori.
    Meglio sarebbe usare una libreria di "logging" (che è molto ben configurabile).

    Poi nei metodi della interfaccia UtenteDAO dichiari che i metodi lanciano SQLException. E così nei metodi di implementazione. Ma se osservi bene, le tue implementazioni NON lanciano SQLException!! Quindi è molto poco coerente.

    E per finire, la closeAll(). Se il rs.close() lancia una eccezione, tu la catturi e poi lanci fuori RuntimeException. Ma così gli altri due close NON li fai!!

    Devi ragionare di più su queste cose ....

    P.S. adesso che ho un attimo di tempo ti scrivo io il findAll() per mostrarti ...
  • Re: Lavorare sulle basi dati con JDBC

    Ecco:
    public class UtenteDAOPostgreSQL implements UtenteDAO {
        // .............
        
        public List<Utente> findAll() throws SQLException {
            try {
                Connection conn = connect();
    
                try {
                    PreparedStatement ps = conn.prepareStatement("SELECT * FROM utenti");
    
                    try {
                        ResultSet rs = ps.executeQuery();
    
                        try {
                            List<Utente> lista = new ArrayList<Utente>();
    
                            while (rs.next()) {
                                Utente utente = new Utente();
                                utente.setId(rs.getInt("id"));
                                utente.setNome(rs.getString("nome"));
                                utente.setPassword(rs.getString("password"));
                                lista.add(utente);
                            }
    
                            return lista;
                        } finally {
                            close(rs);
                        }
                    } finally {
                        close(ps);
                    }
                } finally {
                    close(conn);
                }
            } catch (SQLException e) {
                // logging ...
                throw e;
            }
        }
    
        private Connection connect() throws SQLException {
            try {
                // eventuale logging ...
                Connection conn = DriverManager.getConnection(url, user, password);
                // eventuale logging ...
                return conn;
            } catch (SQLException e) {
                // logging ...  (questo può essere ridondante se si mantiene il logging es. in findAll)
                throw e;
            }
        }
    
        private static void close(AutoCloseable cl) {
            try {
                if (cl != null) {
                    cl.close();
                }
            } catch (Exception e) {
                // logging ...
            }
        }
    
        // ........
    }
    La gestione delle eccezioni nel findAll() è nella forma "classica", con i try-finally annidati per ciascuna risorsa. E' un pelino più lunga. Ma si può eventualmente abbreviare (banalmente compattando i finally su 1 riga).
    La cosa buona è che i close vengono sempre fatti TUTTI. E nota come NON ci siano null assegnati esplicitamente.

    Nota che il close privato è uno solo e va bene per Connection/PreparedStatement/ResultSet semplicemente perché questi tipi estendono AutoCloseable.

    Se ad esempio il rs.getInt() lanciasse un SQLException, questa eccezione è proprio quella che uscirebbe da findAll() (a meno di fare cavolate nel catch al fondo tali da "nascondere" questa eccezione).

    Tieni presente che il try-catch più esterno in findAll() non è "obbligatorio". E' abbastanza tipico gestire/loggare le eccezioni in uno strato più "alto" (es. un Service, un Controller o una Servlet a seconda). Quindi si potrebbe anche non mettere.


    Se si volesse proprio compattare il findAll, una soluzione è usare il try-with-resource introdotto in Java 7. Personalmente, detto sinceramente, a me il try-with-resource non è mai piaciuto tantissimo, perché il close() sulla risorsa è fatto in automatico dalla logica generata dal try-with-resource e non ne hai il controllo. Oltretutto c'è una differenza nel modo in cui il close() sulla risorsa viene affrontato a seconda se il blocco {} del try-with-resource ha lanciato o no una eccezione. Dovresti andare a leggere sul Java Language Specification per capirlo ma te lo lascio come "esercizio" molto .. futuro.

    Se vuoi ti posto anche la versione con il try-with-resource, anche se non mi piace moltissimo ..
  • Re: Lavorare sulle basi dati con JDBC

    Accipicchia, non ci ho pensato ma in effetti è tutta un'altra cosa. Domani lo implemento e ti faccio sapere.
    La mia interfaccia invece va bene, a tuo avviso può andare?
    grazie infinite!
Devi accedere o registrarti per scrivere nel forum
105 risposte