Lavorare sulle basi dati con JDBC

di il
105 risposte

105 Risposte - Pagina 5

  • Re: Lavorare sulle basi dati con JDBC

    giannino1995 ha scritto:


    La mia interfaccia invece va bene, a tuo avviso può andare?
    Sì, la interface UtenteDAO va bene, ha senso.

    C'è però una cosa che non ti è forse chiara. Nelle implementazioni di insert/update/delete hai messo:

    ps = conn.prepareStatement(query, PreparedStatement.RETURN_GENERATED_KEYS);
    ....
    rs = ps.getGeneratedKeys();


    La documentazione però è molto chiara su quel secondo parametro autoGeneratedKeys:

    Creates a default PreparedStatement object that has the capability to retrieve auto-generated keys. The given constant tells the driver whether it should make auto-generated keys available for retrieval. This parameter is ignored if the SQL statement is not an INSERT statement, or an SQL statement able to return auto-generated keys (the list of such statements is vendor-specific).

    Quindi non lo puoi usare per update/delete.
  • Re: Lavorare sulle basi dati con JDBC

    Una cosa così può andare? L'ultimo try non serve giusto?
        public void insert(Utente u) throws SQLException {
            try {
                Connection conn = connect();
                try {
                    PreparedStatement ps = conn.prepareStatement("INSERT INTO utenti (nome, password) VALUES (? , ?)");
                    ps.setString(1, u.getNome());
                    ps.setString(2, u.getPassword());
                    try {
                        ResultSet rs = ps.executeQuery();
                        close(rs);
                    } finally {
                        close(ps);
                    }
                } finally {
                    close(conn);
                }
            } catch (SQLException e) {
                System.out.println("Impossibile connettersi al server PostgreSQL. Connessione non avvenuta.");
                throw e;
            }
        }
    Cosa accadrebbe se al tuo codice aggiungessi:
    throw new RuntimeException(e);
    in close():
        private static void close(AutoCloseable cl) {
            try {
                if (cl != null) {
                    cl.close();
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    Quali i pro e quali i contro? Tu metteresti un semplicissimo logging oppure faresti crachare la webapp?
    Questo codice va messo in tutte le classi QualcosaDAOPostgreSQL?
    static {
            try {
                Class.forName("org.postgresql.Driver");
            } catch (ClassNotFoundException e) {
                throw new ExceptionInInitializerError(e);
            }
        }
    Grazie per tutto
  • Re: Lavorare sulle basi dati con JDBC

    giannino1995 ha scritto:


    Una cosa così può andare? L'ultimo try non serve giusto?
        public void insert(Utente u) throws SQLException {
            try {
                Connection conn = connect();
                try {
                    PreparedStatement ps = conn.prepareStatement("INSERT INTO utenti (nome, password) VALUES (? , ?)");
                    ps.setString(1, u.getNome());
                    ps.setString(2, u.getPassword());
                    try {
                        ResultSet rs = ps.executeQuery();
                        close(rs);
                    } finally {
                        close(ps);
                    }
                } finally {
                    close(conn);
                }
            } catch (SQLException e) {
                System.out.println("Impossibile connettersi al server PostgreSQL. Connessione non avvenuta.");
                throw e;
            }
        }
    No, non va bene. Pensa: se uno dei due ps.setString lanciasse SQLException, tu il ps NON lo chiudi!
    Devi saper "ragionare" sul flusso delle istruzioni e dei try-catch-finally. Questo è fondamentale ...

    giannino1995 ha scritto:


    Cosa accadrebbe se al tuo codice aggiungessi:
    throw new RuntimeException(e);
    in close():
        private static void close(AutoCloseable cl) {
            try {
                if (cl != null) {
                    cl.close();
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    SQLException purtroppo è una eccezione "checked", quindi va sempre dichiarata se deve poter uscire da un metodo e ovviamente va sempre presa in considerazione (non la si può ignorare).

    Se vuoi "spostare" tutto su eccezioni "unchecked" per evitare noie o che, è perfettamente lecito e possibile. Ma allora:
    a) devi farlo in modo coerente
    b) NON usare direttamente RuntimeException, estendila e crea una es. DatabaseException e fai "ragionare" tutto quanto in termini di questa DatabaseException
    c) Fai in modo da mettere il SQLException catturato dentro (come cause, cioè la causa) ciascun oggetto DatabaseException che lanci, così dallo stacktrace è evidente la causa più "interna" del problema.

    giannino1995 ha scritto:


    Questo codice va messo in tutte le classi QualcosaDAOPostgreSQL?
    static {
            try {
                Class.forName("org.postgresql.Driver");
            } catch (ClassNotFoundException e) {
                throw new ExceptionInInitializerError(e);
            }
        }
    Se lo fai più volte di per sé non succede nulla di grave. Ma ha senso farlo una volta sola nella applicazione. Quindi o lo metti in una classe a parte (NON deve per forza essere in un DAO! ... è solo il caricamento di una classe) o trovi qualche altro design per eseguirlo una volta sola.
    Tieni però presente che essendo uno static init block, viene eseguito quando quella classe viene caricata/inizializzata. Ma essere tale, deve venire "usata" da qualcun'altro.
    Quindi potresti spostare in una classe a parte 2 cose: il caricamento del driver E il get della connection. Così sei sicuro che la classe venga "usata".
  • Re: Lavorare sulle basi dati con JDBC

    1.Il codice di insert() presentava in effetti un gravissimo errore, anzi 2. Grazie per avermelo fatto notare.

    2.Il ogni caso quando uso insert() e gli altri due metodi posso non chiudere il ResultSet perché di fatto non lo creo, giusto? (vedi codice)

    3.Ho spostato il codice in altre classi ma il metodo connect() l'ho dovuto rinominare come public, non creo problemi di sicurezza?

    4.E' lecito usare executeUpdate() in questo modo?
    if(ps.executeUpdate()!=0){
    A me funziona perfettamente.

    5.In una webapp reale lasciare tutti i System.out.println() potrebbe essere una cattiva abitudine per la sicurezza?

    Ecco il codice: (Nella webapp importerò tutte le classi in un package a se... non far caso al disordine...)

    DBMS.java
    
    public class DBMS {
    
        // Credenziali di accesso al database locale
        private final String url = "jdbc:postgresql://192.168.99.103:5432/gis";
        private final String user = "eb";
        private final String password = "password";
    
        // Credenziali di accesso al database remoto
        // private final String url = "jdbc:postgresql://192.168.99.103:5432/gis";
        // private final String user = "eb";
        // private final String password = "password";
    
        public String getUrl() {
            return url;
        }
    
        public String getUser() {
            return user;
        }
    
        public String getPassword() {
            return password;
        }
    }
    
    DBMSConnessione.java
    
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    
    public class DBMSConnessione {
    
        static {
            try {
                Class.forName("org.postgresql.Driver");
            } catch (ClassNotFoundException e) {
                System.out.println("Driver JDBC non disponibile.");
                throw new ExceptionInInitializerError(e);
            }
        }
    
        DBMS db = new DBMS();
        private final String url = db.getUrl();
        private final String user = db.getUser();
        private final String password = db.getPassword();
    
        public Connection connect() throws SQLException {
            try {
                Connection conn = DriverManager.getConnection(url, user, password);
                System.out.println("Connesso al server PostgreSQL con successo.");
                return conn;
            } catch (SQLException e) {
                System.out.println("Impossibile connettersi al server PostgreSQL.");
                throw e;
            }
        }
    
        public static void close(AutoCloseable cl) {
            try {
                if (cl != null) {
                    cl.close();
                }
            } catch (Exception e) {
                System.out.println("Impossibile rilasciare la risorsa. Il server rischia di essere sovraccaricato.");
            }
        }
    
    }
    
    DBMSUtente.java
    
    public class DBMSUtente {
        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;
        }
    }
    
    DBMSUtenteDAO.java
    
    import java.sql.SQLException;
    import java.util.List;
    
    public interface DBMSUtenteDAO {
    
        public List<DBMSUtente> findAll() throws SQLException;
    
        public DBMSUtente findByName(String nome) throws SQLException;
    
        public DBMSUtente findById(long id) throws SQLException;
    
        public void insert(DBMSUtente u) throws SQLException;
    
        public void update(DBMSUtente u) throws SQLException;
    
        public void delete(DBMSUtente u) throws SQLException;
    
    }
    
    DBMSUtenteDAOPostgreSQL.java
    
    import java.sql.*;
    import java.util.ArrayList;
    import java.util.List;
    
    public class DBMSUtenteDAOPostgreSQL implements DBMSUtenteDAO {
    
        DBMSConnessione DBMSConnessione = new DBMSConnessione();
    
        public List<DBMSUtente> findAll() throws SQLException {
            try {
                Connection conn = DBMSConnessione.connect();
                try {
                    PreparedStatement ps = conn.prepareStatement("SELECT * FROM utenti");
                    try {
                        ResultSet rs = ps.executeQuery();
                        try {
                            List<DBMSUtente> lista = new ArrayList<DBMSUtente>();
                            while (rs.next()) {
                                DBMSUtente utente = new DBMSUtente();
                                utente.setId(rs.getInt("id"));
                                utente.setNome(rs.getString("nome"));
                                utente.setPassword(rs.getString("password"));
                                lista.add(utente);
                            }
                            if (lista.size()==0) {
                                System.out.println("La tabella è vuota.");
                            } else {
                                System.out.println("E' stato possibile recuperare i record dalla tabella.");
                            }
                            return lista;
                        } finally {
                            DBMSConnessione.close(rs);
                        }
                    } finally {
                        DBMSConnessione.close(ps);
                    }
                } finally {
                    DBMSConnessione.close(conn);
                }
            } catch (SQLException e) {
                System.out.println("Impossibile connettersi al server PostgreSQL. Connessione non avvenuta.");
                throw e;
            }
        }
    
        public DBMSUtente findByName(String nome) throws SQLException {
            try {
                Connection conn = DBMSConnessione.connect();
                try {
                    PreparedStatement ps = conn.prepareStatement("SELECT * FROM utenti WHERE nome = ?");
                    try {
                        ps.setString(1, nome);
                        ResultSet rs = ps.executeQuery();
                        try {
                            DBMSUtente utente = new DBMSUtente();
                            while (rs.next()) {
                                utente.setId(rs.getInt("id"));
                                utente.setNome(rs.getString("nome"));
                                utente.setPassword(rs.getString("password"));
                            }
                            if (utente.getNome()!=null) {
                                System.out.println("E' stato possibile trovare il record.");
                            } else {
                                System.out.println("Non è stato possibile trovare il record.");
                            }
                            return utente;
                        } finally {
                            DBMSConnessione.close(rs);
                        }
                    } finally {
                        DBMSConnessione.close(ps);
                    }
                } finally {
                    DBMSConnessione.close(conn);
                }
            } catch (SQLException e) {
                System.out.println("Impossibile connettersi al server PostgreSQL. Connessione non avvenuta.");
                throw e;
            }
        }
    
        public DBMSUtente findById(long id) throws SQLException {
            try {
                Connection conn = DBMSConnessione.connect();
                try {
                    PreparedStatement ps = conn.prepareStatement("SELECT * FROM utenti WHERE id = ?");
                    try {
                        ps.setLong(1, id);
                        ResultSet rs = ps.executeQuery();
                        try {
                            DBMSUtente utente = new DBMSUtente();
                            while (rs.next()) {
                                utente.setId(rs.getInt("id"));
                                utente.setNome(rs.getString("nome"));
                                utente.setPassword(rs.getString("password"));
                            }
                            if (utente.getNome()!=null) {
                                System.out.println("E' stato possibile trovare il record.");
                            } else {
                                System.out.println("Non è stato possibile trovare il record.");
                            }
                            return utente;
                        } finally {
                            DBMSConnessione.close(rs);
                        }
                    } finally {
                        DBMSConnessione.close(ps);
                    }
                } finally {
                    DBMSConnessione.close(conn);
                }
            } catch (SQLException e) {
                System.out.println("Impossibile connettersi al server PostgreSQL. Connessione non avvenuta.");
                throw e;
            }
        }
    
        public void insert(DBMSUtente u) throws SQLException {
            try {
                Connection conn = DBMSConnessione.connect();
                try {
                    PreparedStatement ps = conn.prepareStatement("INSERT INTO utenti (nome, password) VALUES (? , ?)");
                    try {
                        ps.setString(1, u.getNome());
                        ps.setString(2, u.getPassword());
                        ps.executeUpdate();
                        System.out.println("Nuovo record aggiunto alla tabella.");
                    } catch (SQLException e){
                        System.out.println("Non è stato possibile inserire il record.");
                    }
                    finally {
                        DBMSConnessione.close(ps);
                    }
                } finally {
                    DBMSConnessione.close(conn);
                }
            } catch (SQLException e) {
                System.out.println("Impossibile connettersi al server PostgreSQL. Connessione non avvenuta.");
                throw e;
            }
        }
    
        public void update(DBMSUtente u) throws SQLException {
            try {
                Connection conn = DBMSConnessione.connect();
                try {
                    String query = "UPDATE utenti SET nome = ?, password = ? WHERE id = ?";
                    PreparedStatement ps = conn.prepareStatement(query);
                    try {
                        ps.setString(1, u.getNome());
                        ps.setString(2, u.getPassword());
                        ps.setLong(3, u.getId());
                        if(ps.executeUpdate()!=0){
                            System.out.println("E' stato aggiornato il record.");
                        }else{
                            System.out.println("Record non trovato.");
                        }
                    } catch (SQLException e){
                        System.out.println("Non è stato possibile aggiornare il record.");
                    }
                    finally {
                        DBMSConnessione.close(ps);
                    }
                } finally {
                    DBMSConnessione.close(conn);
                }
            } catch (SQLException e) {
                System.out.println("Impossibile connettersi al server PostgreSQL. Connessione non avvenuta.");
                throw e;
            }
        }
    
        public void delete(DBMSUtente u) throws SQLException {
            try {
                Connection conn = DBMSConnessione.connect();
                try {
                    PreparedStatement ps = conn.prepareStatement("DELETE FROM utenti WHERE nome = ?");
                    try {
                        ps.setString(1, u.getNome());
                        if(ps.executeUpdate()!=0){
                            System.out.println("E' stato cancellato il record.");
                        }else{
                            System.out.println("Record non trovato.");
                        }
                    } catch (SQLException e){
                        System.out.println("Non è stato possibile cancellare il record.");
                    }
                    finally {
                        DBMSConnessione.close(ps);
                    }
                } finally {
                    DBMSConnessione.close(conn);
                }
            } catch (SQLException e) {
                System.out.println("Impossibile connettersi al server PostgreSQL. Connessione non avvenuta.");
                throw e;
            }
        }
    
    }
    
    
  • Re: Lavorare sulle basi dati con JDBC

    giannino1995 ha scritto:


    2.Il ogni caso quando uso insert() e gli altri due metodi posso non chiudere il ResultSet perché di fatto non lo creo, giusto? (vedi codice)
    Non l'avevo notato prima ma avevi usato executeQuery() per la INSERT. executeQuery() si usa solo per quelle query che danno un result-set. Per INSERT/UPDATE/DELETE non si deve usare.

    giannino1995 ha scritto:


    3.Ho spostato il codice in altre classi ma il metodo connect() l'ho dovuto rinominare come public, non creo problemi di sicurezza?
    Se mi parli di "sicurezza" dovresti anche precisare quale ritieni sia il "pericolo". Che qualcuno (dove/da dove?) possa invocare quel metodo public?

    Tieni presente una cosa: i dati di accesso sono "in chiaro" in quella classe DBMS (e anche nel .class generato!). Quindi chiunque li vedesse/sapesse, potrebbe accedere comunque al DB anche al di fuori di Java. Quindi non è tanto il metodo "public" il problema.

    giannino1995 ha scritto:


    4.E' lecito usare executeUpdate() in questo modo?
    if(ps.executeUpdate()!=0){
    A me funziona perfettamente.
    Sì, è lecito. Ma bisogna vedere se ha senso testare o no il numero di righe interessate. Se fai un update sì (mi aspetto che il record ci sia). Se fai un delete, è meno importante (il record potrebbe essere già stato eliminato).

    giannino1995 ha scritto:


    5.In una webapp reale lasciare tutti i System.out.println() potrebbe essere una cattiva abitudine per la sicurezza?
    Dipende dove viene buttato il System.out. Come ho detto, dipende. Dipende dal server e da come è configurato e/o avviato (da una console? dal sistema in background? ecc..).

    E dipende ovviamente cosa ci scrivi. Se logghi password o dati "sensibili", sì, ci sono sicuramente questioni di sicurezza.

    giannino1995 ha scritto:


    Ecco il codice: (Nella webapp importerò tutte le classi in un package a se... non far caso al disordine...)
    Giusto alcune note:

    1) findByName/findById (il discorso è quasi uguale)

    Perché hai usato while (rs.next()) ? Ha poco senso, mi aspetto 1 record solo.
    E se non viene trovato tu ora restituisci un oggetto DBMSUtente ma con i valori di "default". Che è difficile poi da maneggiare, nel senso: come fa il chiamante a capire se quell'oggetto DBMSUtente indica che non è stato trovato? Guarda che il id sia es. 0? Guarda che nome e password siano entrambi null? NO è scomodo!!
    if (rs.next()) {
        DBMSUtente utente = new DBMSUtente();
        // ....
        return utente;
    } else {
        return null;   // non trovato!!!
    }
    Stop, tutto qui.

    2) insert

    Nel insert ha senso (molto!) ottenere la chiave generata. Altrimenti quale "aggancio" avresti in seguito per fare update o altro dell'utente??
    Quindi puoi fare una (o entrambe) delle seguenti cose:
    - restituire il id generato
    - impostare il id nell'oggetto DBMSUtente che il metodo riceve

    3) delete

    Il delete sarebbe meglio per id .. non per nome. Questo, in generale.
  • Re: Lavorare sulle basi dati con JDBC

    1) Hai perfettamente ragione, non ti si può mai dare torto. Molto meglio ritornare null ed usare if. Bravissimo, grazie mille!
    2) Ho aggiunto il return in tutto, anche in delete ed update nel caso servisse. Grazie
    3) In effetti ha più senso. Grazie
    4) Per quanto riguarda la sicurezza mi sembra di capire che l’unica cosa sbagliata è qui:
     package DBMS;
    
    public class DBMS {
    
        // Credenziali di accesso al database locale
        private final String url = "jdbc:postgresql://192.168.99.103:5432/gis";
        private final String user = "eb";
        private final String password = "password";
    
        // Credenziali di accesso al database remoto
        // private final String url = "jdbc:postgresql://192.168.99.103:5432/gis";
        // private final String user = "eb";
        // private final String password = "password";
    
        public String getUrl() {
            return url;
        }
    
        public String getUser() {
            return user;
        }
    
        public String getPassword() {
            return password;
        }
    }
    
    La password in chiaro non è cosa buona, giusto?

    P.S.: Anzi ti posto ugualmente tutto:
    package DBMS;
    
    import java.sql.*;
    import java.util.ArrayList;
    import java.util.List;
    
    
    public class DBMSUtenteDAOPostgreSQL implements DBMSUtenteDAO {
    
        DBMSConnessione DBMSConnessione = new DBMSConnessione();
    
        public List<DBMSUtente> findAll() throws SQLException {
            try {
                Connection conn = DBMSConnessione.connect();
                try {
                    PreparedStatement ps = conn.prepareStatement("SELECT * FROM utenti");
                    try {
                        ResultSet rs = ps.executeQuery();
                        try {
                            List<DBMSUtente> lista = new ArrayList<DBMSUtente>();
                            while (rs.next()) {
                                DBMSUtente utente = new DBMSUtente();
                                utente.setId(rs.getInt("id"));
                                utente.setNome(rs.getString("nome"));
                                utente.setPassword(rs.getString("password"));
                                lista.add(utente);
                            }
                            if (lista.size()==0) {
                                System.out.println("La tabella è vuota.");
                                return null;
                            } else {
                                System.out.println("E' stato possibile recuperare i record dalla tabella.");
                                return lista;
                            }
                        } finally {
                            DBMSConnessione.close(rs);
                        }
                    } finally {
                        DBMSConnessione.close(ps);
                    }
                } finally {
                    DBMSConnessione.close(conn);
                }
            } catch (SQLException e) {
                System.out.println("Impossibile connettersi al server PostgreSQL. Connessione non avvenuta.");
                throw e;
            }
        }
    
        public DBMSUtente findByNome(String nome) throws SQLException {
            try {
                Connection conn = DBMSConnessione.connect();
                try {
                    PreparedStatement ps = conn.prepareStatement("SELECT * FROM utenti WHERE nome = ?");
                    try {
                        ps.setString(1, nome);
                        ResultSet rs = ps.executeQuery();
                        try {
                            DBMSUtente utente = new DBMSUtente();
                            if (rs.next()) {
                                utente.setId(rs.getInt("id"));
                                utente.setNome(rs.getString("nome"));
                                utente.setPassword(rs.getString("password"));
                                System.out.println("E' stato possibile trovare il record.");
                                return utente;
                            } else {
                                System.out.println("Non è stato possibile trovare il record.");
                                return null;
                            }
                        } finally {
                            DBMSConnessione.close(rs);
                        }
                    } finally {
                        DBMSConnessione.close(ps);
                    }
                } finally {
                    DBMSConnessione.close(conn);
                }
            } catch (SQLException e) {
                System.out.println("Impossibile connettersi al server PostgreSQL. Connessione non avvenuta.");
                throw e;
            }
        }
    
        public DBMSUtente findById(long id) throws SQLException {
            try {
                Connection conn = DBMSConnessione.connect();
                try {
                    PreparedStatement ps = conn.prepareStatement("SELECT * FROM utenti WHERE id = ?");
                    try {
                        ps.setLong(1, id);
                        ResultSet rs = ps.executeQuery();
                        try {
                            DBMSUtente utente = new DBMSUtente();
                            if (rs.next()) {
                                utente.setId(rs.getInt("id"));
                                utente.setNome(rs.getString("nome"));
                                utente.setPassword(rs.getString("password"));
                                System.out.println("E' stato possibile trovare il record.");
                                return utente;
                            } else {
                                System.out.println("Non è stato possibile trovare il record.");
                                return null;
                            }
                        } finally {
                            DBMSConnessione.close(rs);
                        }
                    } finally {
                        DBMSConnessione.close(ps);
                    }
                } finally {
                    DBMSConnessione.close(conn);
                }
            } catch (SQLException e) {
                System.out.println("Impossibile connettersi al server PostgreSQL. Connessione non avvenuta.");
                throw e;
            }
        }
    
        public long insert(DBMSUtente u) throws SQLException {
            try {
                Connection conn = DBMSConnessione.connect();
                try {
                    PreparedStatement ps = conn.prepareStatement("INSERT INTO utenti (nome, password) VALUES (? , ?)");
                    try {
                        ps.setString(1, u.getNome());
                        ps.setString(2, u.getPassword());
                        System.out.println("E' stato possibile inserire il record.");
                        return ps.executeUpdate();
                    } catch (SQLException e1){
                        System.out.println("Non è stato possibile inserire il record.");
                        return 0;
                    } catch (Exception e2) {
                        System.out.println("Non è stato possibile inserire il record.");
                        return 0;
                    }
                    finally {
                        DBMSConnessione.close(ps);
                    }
                } finally {
                    DBMSConnessione.close(conn);
                }
            } catch (SQLException e) {
                System.out.println("Impossibile connettersi al server PostgreSQL. Connessione non avvenuta.");
                return 0;
            }
        }
    
        public long update(DBMSUtente u) throws SQLException {
            try {
                Connection conn = DBMSConnessione.connect();
                try {
                    String query = "UPDATE utenti SET nome = ?, password = ? WHERE id = ?";
                    PreparedStatement ps = conn.prepareStatement(query);
                    try {
                        ps.setString(1, u.getNome());
                        ps.setString(2, u.getPassword());
                        ps.setLong(3, u.getId());
                        long record = ps.executeUpdate();
                        if(record!=0){
                            System.out.println("E' stato aggiornato il record.");
                        }else{
                            System.out.println("Record non trovato.");
                        }
                        return record;
                    } catch (SQLException e1){
                        System.out.println("Non è stato possibile editare il record.");
                        return 0;
                    } catch (Exception e2) {
                        System.out.println("Non è stato possibile editare il record.");
                        return 0;
                    }
                    finally {
                        DBMSConnessione.close(ps);
                    }
                } finally {
                    DBMSConnessione.close(conn);
                }
            } catch (SQLException e) {
                System.out.println("Impossibile connettersi al server PostgreSQL. Connessione non avvenuta.");
                return 0;
            }
        }
    
        public long delete(DBMSUtente u) throws SQLException {
            try {
                Connection conn = DBMSConnessione.connect();
                try {
                    PreparedStatement ps = conn.prepareStatement("DELETE FROM utenti WHERE id = ?");
                    try {
                        ps.setLong(1, u.getId());
                        long record = ps.executeUpdate();
                        if(record!=0){
                            System.out.println("E' stato cancellato il record.");
                        }else{
                            System.out.println("Record non trovato.");
                        }
                        return record;
                    } catch (SQLException e1){
                        System.out.println("Non è stato possibile cancellare il record.");
                        return 0;
                    } catch (Exception e2) {
                        System.out.println("Non è stato possibile cancellare il record.");
                        return 0;
                    }
                    finally {
                        DBMSConnessione.close(ps);
                    }
                } finally {
                    DBMSConnessione.close(conn);
                }
            } catch (SQLException e) {
                System.out.println("Impossibile connettersi al server PostgreSQL. Connessione non avvenuta.");
                return 0;
            }
        }
    
    }
    è da testare ma dovrebbe andare...
  • Re: Lavorare sulle basi dati con JDBC

    1) in generale la "configurazione" (ip del DBMS, utente, password, ecc) si tengono in un FILE separato (ad esempio un file '.properties' , '.json' o '.xml')
    2) anche le query si tengono, spesso, in un file separato, perche' possono dover essere modificate
    3) NON SI USA MAI il "System.out" per fare logging, ma librerie dedicate.

    Java ha la sua implementazione, ma c'e' anche Log4J, molto famosa, o Apache Commons Logging
  • Re: Lavorare sulle basi dati con JDBC

    giannino1995 ha scritto:


    1) Hai perfettamente ragione, non ti si può mai dare torto. Molto meglio ritornare null ed usare if. Bravissimo, grazie mille!
    Lo dico solo completezza, da Java 8 in poi ci sarebbe un'altra possibilità oltre al null "secco": usare un Optional<DBMSUtente>
    Ma quasi sicuramente è un argomento che non hai ancora affrontato, quindi lasciamo perdere.

    giannino1995 ha scritto:


    La password in chiaro non è cosa buona, giusto?
    Sì la password in chiaro ovviamente non è il massimo. Ma se andiamo su queste questioni, allora si dovrebbero valutare tecniche che usano eventualmente cifratura, ecc...

    Stai facendo una esercitazione, lascia perdere questi dettagli che quasi sicuramente non sono "richiesti".

    giannino1995 ha scritto:


    2) Ho aggiunto il return in tutto, anche in delete ed update nel caso servisse.
    Scusa ma .... ragioni sulle cose che ti vengono dette???

    1) findAll: non è di per sé sbagliato ritornare null se lista vuota. Ma quasi sempre una lista vuota è generalmente meglio di un null "secco", specialmente se è lecito/probabile che una query "find all" (o similare) possa non trovare dati.

    2) findByNome/findById: perché hai creato l'oggetto DBMSUtente prima del if? Se guardi cosa ho fatto prima, vedi che l'ho creato nel corpo del if.

    3) insert: perché fai return ps.executeUpdate(); ??
    Te l'ho detto prima: per insert devi prendere la CHIAVE GENERATA, perché al chiamante potrebbe servire per fare altre cose.

    4) insert/update/delete: perché nel catch fai un return 0 ?? Se hai un SQLException ... hai un SQLException, va bene del "logging" ma lo devi rilanciare fuori. E perché all'interno fai due catch, uno con SQLException e l'altro con Exception, tra l'altro esattamente uguali?? Che senso ha??

    5) delete: pensandoci, potrebbe avere senso restituire un boolean: true = trovato (e cancellato), false = non trovato.

    Vuoi RAGIONARE su questi punti?
  • Re: Lavorare sulle basi dati con JDBC

    1) ok;
    2) ok;
    3) ok;
    4) se qualcosa va storto devo informare il chiamante con uno 0 per INSERT e false con UPDATE e DELETE;
    5) ok;
    6) il tuo costrutto non mi piace perché è rischioso:
    Se inserisco codice dopo il PreparedStatement faccio errori gravi. Non mi piace molto. Il primo codice è più macchinoso ma più chiaro.
    Di questo che ne pensi:
    
    package DBMS;
    
    import java.sql.*;
    import java.util.ArrayList;
    import java.util.List;
    
    public class DBMSUtenteDAOPostgreSQL implements DBMSUtenteDAO {
    
        DBMSConnessione DBMSConnessione = new DBMSConnessione();
    
        public List<DBMSUtente> findAll() throws SQLException {
            try {
                Connection conn = DBMSConnessione.connect();
                try {
                    PreparedStatement ps = conn.prepareStatement("SELECT * FROM utenti");
                    try {
                        ResultSet rs = ps.executeQuery();
                        try {
                            List<DBMSUtente> lista = new ArrayList<DBMSUtente>();
                            while (rs.next()) {
                                DBMSUtente utente = new DBMSUtente();
                                utente.setId(rs.getInt("id"));
                                utente.setNome(rs.getString("nome"));
                                utente.setPassword(rs.getString("password"));
                                lista.add(utente);
                            }
                            if (lista.size()==0) {
                                System.out.println("La tabella è vuota.");
                                lista = null;
                            } else {
                                System.out.println("E' stato possibile recuperare i record dalla tabella.");
                            }
                            return lista;
                        } finally {
                            DBMSConnessione.close(rs);
                        }
                    } finally {
                        DBMSConnessione.close(ps);
                    }
                } finally {
                    DBMSConnessione.close(conn);
                }
            } catch (SQLException e) {
                System.out.println("Impossibile connettersi al server PostgreSQL. Connessione non avvenuta.");
                throw e;
            }
        }
    
        public DBMSUtente findByNome(String nome) throws SQLException {
            try {
                Connection conn = DBMSConnessione.connect();
                try {
                    PreparedStatement ps = conn.prepareStatement("SELECT * FROM utenti WHERE nome = ?");
                    try {
                        ps.setString(1, nome);
                        ResultSet rs = ps.executeQuery();
                        try {
                            if (rs.next()) {
                                DBMSUtente utente = new DBMSUtente();
                                utente.setId(rs.getInt("id"));
                                utente.setNome(rs.getString("nome"));
                                utente.setPassword(rs.getString("password"));
                                System.out.println("E' stato possibile trovare il record.");
                                return utente;
                            } else {
                                DBMSUtente utente = null;
                                System.out.println("Non è stato possibile trovare il record.");
                                return utente;
                            }
                        } finally {
                            DBMSConnessione.close(rs);
                        }
                    } finally {
                        DBMSConnessione.close(ps);
                    }
                } finally {
                    DBMSConnessione.close(conn);
                }
            } catch (SQLException e) {
                System.out.println("Impossibile connettersi al server PostgreSQL. Connessione non avvenuta.");
                throw e;
            }
        }
    
        public DBMSUtente findById(long id) throws SQLException {
            try {
                Connection conn = DBMSConnessione.connect();
                try {
                    PreparedStatement ps = conn.prepareStatement("SELECT * FROM utenti WHERE id = ?");
                    try {
                        ps.setLong(1, id);
                        ResultSet rs = ps.executeQuery();
                        try {
                            if (rs.next()) {
                                DBMSUtente utente = new DBMSUtente();
                                utente.setId(rs.getInt("id"));
                                utente.setNome(rs.getString("nome"));
                                utente.setPassword(rs.getString("password"));
                                System.out.println("E' stato possibile trovare il record.");
                                return utente;
                            } else {
                                DBMSUtente utente = null;
                                System.out.println("Non è stato possibile trovare il record.");
                                return utente;
                            }
                        } finally {
                            DBMSConnessione.close(rs);
                        }
                    } finally {
                        DBMSConnessione.close(ps);
                    }
                } finally {
                    DBMSConnessione.close(conn);
                }
            } catch (SQLException e) {
                System.out.println("Impossibile connettersi al server PostgreSQL. Connessione non avvenuta.");
                throw e;
            }
        }
    
        public long insert(DBMSUtente u) throws SQLException {
            try {
                Connection conn = DBMSConnessione.connect();
                try {
                    String query = "INSERT INTO utenti (nome, password) VALUES (? , ?)";
                    PreparedStatement ps = conn.prepareStatement(query);
                    try {
                        ps.setString(1, u.getNome());
                        ps.setString(2, u.getPassword());
                        System.out.println("E' stato possibile inserire il record.");
                        ps.executeUpdate(query ,PreparedStatement.RETURN_GENERATED_KEYS);
                        ResultSet rs = ps.getGeneratedKeys();
                        try{
                            long key = 0;
                            if (rs.next()) {
                                key = rs.getLong(1);
                            }
                            return key;
                        }finally{
                            DBMSConnessione.close(rs);
                        }
                    } catch (SQLException e1){
                        System.out.println("Non è stato possibile inserire il record.");
                        return 0;
                    } catch (Exception e2) {
                        System.out.println("Non è stato possibile inserire il record.");
                        return 0;
                    }
                    finally {
                        DBMSConnessione.close(ps);
                    }
                } finally {
                    DBMSConnessione.close(conn);
                }
            } catch (SQLException e) {
                System.out.println("Impossibile connettersi al server PostgreSQL. Connessione non avvenuta.");
                return 0;
            }
        }
    
        public boolean update(DBMSUtente u) throws SQLException {
            try {
                Connection conn = DBMSConnessione.connect();
                try {
                    String query = "UPDATE utenti SET nome = ?, password = ? WHERE id = ?";
                    PreparedStatement ps = conn.prepareStatement(query);
                    try {
                        ps.setString(1, u.getNome());
                        ps.setString(2, u.getPassword());
                        ps.setLong(3, u.getId());
                        long record = ps.executeUpdate();
                        if(record!=0){
                            System.out.println("E' stato aggiornato il record.");
                            return true;
                        }else{
                            System.out.println("Record non trovato.");
                            return false;
                        }
                    } catch (SQLException e1){
                        System.out.println("Non è stato possibile editare il record.");
                        return false;
                    } catch (Exception e2) {
                        System.out.println("Non è stato possibile editare il record.");
                        return false;
                    }
                    finally {
                        DBMSConnessione.close(ps);
                    }
                } finally {
                    DBMSConnessione.close(conn);
                }
            } catch (SQLException e) {
                System.out.println("Impossibile connettersi al server PostgreSQL. Connessione non avvenuta.");
                return false;
            }
        }
    
        public boolean delete(DBMSUtente u) throws SQLException {
            try {
                Connection conn = DBMSConnessione.connect();
                try {
                    PreparedStatement ps = conn.prepareStatement("DELETE FROM utenti WHERE id = ?");
                    try {
                        ps.setLong(1, u.getId());
                        long record = ps.executeUpdate();
                        if(record!=0){
                            System.out.println("E' stato cancellato il record.");
                            return true;
                        }else{
                            System.out.println("Record non trovato.");
                            return false;
                        }
                    } catch (SQLException e1){
                        System.out.println("Non è stato possibile cancellare il record.");
                        return false;
                    } catch (Exception e2) {
                        System.out.println("Non è stato possibile cancellare il record.");
                        return false;
                    }
                    finally {
                        DBMSConnessione.close(ps);
                    }
                } finally {
                    DBMSConnessione.close(conn);
                }
            } catch (SQLException e) {
                System.out.println("Impossibile connettersi al server PostgreSQL. Connessione non avvenuta.");
                return false;
            }
        }
    
    
    }
    
    A me non piace molto… Il codice è ancora da testare.
  • Re: Lavorare sulle basi dati con JDBC

    giannino1995 ha scritto:


    4) se qualcosa va storto devo informare il chiamante con uno 0 per INSERT e false con UPDATE e DELETE;
    NOOO. Se qualcosa va storto (= SQLException, qualcosa di grave), SQLException deve USCIRE dal metodo.
    Se non la fai uscire hai già innanzitutto un comportamento difforme rispetto agli altri metodi (oltre al fatto che non è più vero il throws SQLException).

    giannino1995 ha scritto:


    6) il tuo costrutto non mi piace perché è rischioso:
    A cosa ti riferisci esattamente??
  • Re: Lavorare sulle basi dati con JDBC

    @giannino1995, quella sequenza di try/finally innestate e' un errore ed una inutile complicazione del codice.

    RAGIONA: c'e' una soluzione MOLTO piu' semplice, basata sulle PROPRIETA' della conessione/statement/resultset, dell'ordine in cui si creano e dell'ordine in cui si chiudono!

    Le eccezzioni:

    1) si propagano cosi' come sono
    2) si propagano ma si wrappano con un'altro tipo di eccezzione
    3) si intercettano, SI LOGGANO e NON SI PROPAGANO.

    Si intercettano SOLO nel punto in cui l'applicazione ha il controllo della situazione e puo' continuare correttamente a funzionare.

    Il "finally" si usa APPUNTO per rilasciare le risorse sia durante la normale esecuzione, SIA durante la propagazione di un'eccezzione.

    Nel "finally" e' FONDAMENTALE assicurarsi di non generare un nuovo tipo di eccezzione.
    Quindi il codice scritto va PENSATO per bene, perche' deve poter essere eseguito IN TUTTI I POSSIBILI MODI.


    Le connessioni SI APRONO E SI CHIUDONO ad ogni statement, o gruppo di statement che dovrebbero essere eseguiti all'interno di una transazione.

    Questo IN TEORIA.

    In pratica, la creazione di una connessione (con relativa autenticazione dell'utente) e' un'attivta ESTREMAMENTE LENTA, e quindi va fatta il minor numero di volte possibile.

    Per questo motivo si usano i "connection pool", oggetti che tengono un "pool" di conessioni sempre aperte in modo da riusarle.

    TU pensi di aprirla/chiuderla, in realta' la connessione viene presa dal pool e rimandata nel pool.

    Infine, ESISTE una nuova sintassi per il try, pensata APPOSITAMENTE per questo tipo di situazioni:
    
    	try(Connection conn = DBMSConnessione.connect()) {
    	   ...
    	}
    
    Ma questa e' un'altra storia
  • Re: Lavorare sulle basi dati con JDBC

    Questo thread sta diventando un CORSO ONLINE PER GIANNINO

    Dopo 5 pagine non so più quale era il problema iniziale e non si comprende se è stato risolto ...
  • Re: Lavorare sulle basi dati con JDBC

    oregon ha scritto:


    Questo thread sta diventando un CORSO ONLINE PER GIANNINO
    Beh dai, sto usufruendo anch'io che sono un po' arrugginito coi database.

    Grazie andbin del ripasso
  • Re: Lavorare sulle basi dati con JDBC

    migliorabile ha scritto:


    quella sequenza di try/finally innestate e' un errore ed una inutile complicazione del codice.
    Beh no, dai (e non perché l'ho suggerita io) non è proprio un "errore". E' una forma classica/completa. Sicuramente più verbosa e annidata ma perlomeno i finally danno la garanzia di tutte le chiusure in cascata.

    Poi si potrebbe anche fare qualcosa di meglio. C'è una cosa che non ho detto a giannino (e lui i javadoc non li legge ..): la documentazione di Statement dice chiaramente che When a Statement object is closed, its current ResultSet object, if one exists, is also closed.
    Quindi si potrebbe anche non chiudere il ResultSet, purché si chiuda in modo certo il (Prepared)Statement. Ma non volevo confondergli le idee ...
    Già una interfaccia di "strategia" come quel RowMapper non l'ha capita (è OOP, non astrofisica ..) ... diventa pure difficile proporgli le cose.
    Gli ho proposto quella forma solo per completezza/correttezza.

    Certo, ci sarebbe il try-with-resource. Come ho già detto in precedenza, non mi è mai piaciuto tantissimo, perché i close sono "nascosti" e non si può ad esempio "zittire" le eccezioni di un close().
  • Re: Lavorare sulle basi dati con JDBC

    @andbin: hai ragione!

    Diamo a Cesare quel che e' di Cesare!

Devi accedere o registrarti per scrivere nel forum
105 risposte