Lavorare sulle basi dati con JDBC

di il
105 risposte

105 Risposte - Pagina 6

  • Re: Lavorare sulle basi dati con JDBC

    andbin ha scritto:


    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.

    1.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).
    1.La mia intenzione era evitare che il codice si bloccasse ma in effetti se qualcosa non funziona la webapp va bloccata. Penserò a questo aspetto quando ritorno alla webapp.

    andbin ha scritto:


    giannino1995 ha scritto:


    6) il tuo costrutto non mi piace perché è rischioso:
    A cosa ti riferisci esattamente??
    2.Mi riferisco al fatto che se lancio un ps.setString() dopo un PreparedStatement senza aprire un nuovo Try commetto un errore. Inoltre tutti questi finaly non mi piacciano, rendono il codice difficile da leggere. La tua soluzione è validissima, non travisare le mie parole ma preferisco avere un unico finaly nel codice.

    3.Un’altra cosa che ho notato testando il nuovo codice (vedi a fine post), ma che sicuramente si verifica anche nel precedente, è che quando tento di mettere un record che poi non può essere inserito per un motivo o per l’altro nel DB viene perso un id come quando scrivo un record e poi lo cancello. Detto in altro modo se tento di aggiungere un record che esiste già il mio metodo mi avverte e non aggiunge nulla al DB ma al passaggio successivo (un nuovo INSERT) il DB salta un id. Posso tranquillamente fregarmene oppure devo evitare questo comportamento? Rischio di ridurre la capienza massima del mio DB?

    4.Nel codice trovi due nuovi metodi:
    isAcceptable(): è una classe aggiunta a DBMSUtente.java per verificare che la user e la password non siano nulle o contengano degli spazi oppure ancora prive di caratteri.
    DBMSConnessione.close(rs , ps , c): è un semplice costruttore del tuo close(AutoCloseable c).
    
    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 {
            Connection c = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            try {
                c = DBMSConnessione.connect();
                ps = c.prepareStatement("SELECT * FROM utenti");
                rs = ps.executeQuery();
                List<DBMSUtente> lista = new ArrayList<DBMSUtente>();
                while (rs.next()) {
                    DBMSUtente utente = new DBMSUtente();
                    utente.setId(rs.getLong("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;
            } catch (Exception e) {
                System.out.println("Non è stato possibile recuperare i record dalla tabella.");
                List<DBMSUtente> lista = null;
                return lista;
            } finally {
                DBMSConnessione.close(rs , ps , c);
            }
        }
    
        public DBMSUtente findByNome(String nome) throws SQLException {
            Connection c = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            try {
                c = DBMSConnessione.connect();
                ps = c.prepareStatement("SELECT * FROM utenti WHERE nome = ?");
                ps.setString(1, nome);
                rs = ps.executeQuery();
                if (rs.next()) {
                    DBMSUtente utente = new DBMSUtente();
                    utente.setId(rs.getLong("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;
                }
            } catch (Exception e) {
                System.out.println("Non è stato possibile recuperare il record dalla tabella.");
                DBMSUtente utente = null;
                return utente;
            } finally {
                DBMSConnessione.close(rs , ps , c);
            }
        }
    
        public DBMSUtente findById(Long id) throws SQLException {
            Connection c = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            try {
                c = DBMSConnessione.connect();
                ps = c.prepareStatement("SELECT * FROM utenti WHERE id = ?");
                ps.setLong(1, id);
                rs = ps.executeQuery();
                if (rs.next()) {
                    DBMSUtente utente = new DBMSUtente();
                    utente.setId(rs.getLong("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;
                }
            } catch (Exception e) {
                System.out.println("Non è stato possibile recuperare il record dalla tabella.");
                DBMSUtente utente = null;
                return utente;
            } finally {
                DBMSConnessione.close(rs , ps , c);
            }
        }
    
        public Long insert(DBMSUtente u) throws SQLException {
            Connection c = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            try {
                if(!u.isAcceptable()) {
                    System.out.println("Non è stato possibile inserire il record.");
                    return 0L;
                }
                c = DBMSConnessione.connect();
                ps = c.prepareStatement("INSERT INTO utenti (nome, password) VALUES (? , ?)");
                ps.setString(1, u.getNome());
                ps.setString(2, u.getPassword());
                ps.executeUpdate(ps.toString(), PreparedStatement.RETURN_GENERATED_KEYS);
                rs = ps.getGeneratedKeys();
                Long idRiga = 0L;
                if (rs.next()) {
                    idRiga = rs.getLong(1);
                    System.out.println("E' stato possibile inserire il record nell'id: " + idRiga);
                }
                return idRiga;
            } catch (Exception e) {
                System.out.println("Non è stato possibile inserire il record.");
                return 0L;
            } finally {
                DBMSConnessione.close(rs , ps , c);
            }
        }
    
        public boolean update(DBMSUtente u) throws SQLException {
            Connection c = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            try {
                if(!u.isAcceptable()) {
                    System.out.println("Non è stato possibile inserire il record.");
                    return false;
                }
                c = DBMSConnessione.connect();
                ps = c.prepareStatement("UPDATE utenti SET nome = ?, password = ? WHERE id = ?");
                ps.setString(1, u.getNome());
                ps.setString(2, u.getPassword());
                ps.setLong(3, u.getId());
                Long numRighe = Long.valueOf(ps.executeUpdate());
                if(numRighe!=0){
                    System.out.println("E' stato aggiornato il record.");
                    return true;
                }else{
                    System.out.println("Record non trovato.");
                    return false;
                }
            } catch (Exception e) {
                System.out.println("Non è stato possibile inserire il record.");
                return false;
            } finally {
                DBMSConnessione.close(rs , ps , c);
            }
        }
    
        public boolean delete(DBMSUtente u) throws SQLException {
            Connection c = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            try {
                c = DBMSConnessione.connect();
                ps = c.prepareStatement("DELETE FROM utenti WHERE id = ?");
                ps.setLong(1, u.getId());
                Long numRighe = Long.valueOf(ps.executeUpdate());
                if(numRighe!=0){
                    System.out.println("E' stato cancellato il record.");
                    return true;
                }else{
                    System.out.println("Record non trovato.");
                    return false;
                }
            } catch (Exception e) {
                System.out.println("Non è stato possibile cancellare il record.");
                return false;
            } finally {
                DBMSConnessione.close(rs , ps , c);
            }
        }
    
    }
    
    
    5.Bellezza, grazia ed eleganza a parte la mia classe può andare oppure a tuo avviso ha gravi problemi di funzionalità e sicurezza?

    migliorabile ha scritto:


    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
    Grazie migliorabile per i consigli.

    A.Quindi creeresti un file di questo tipo:
    ...\src\main\webapp\WEB-INF\DBMS.json
    e salveresti sopra di esso ip, utente e password? Useresti quindi la mia classe attuale DBMS.java non per conservare le credenziali del DB ma per leggere le informazioni da DBMS.json, ho capito bene?

    B.Nel mio caso ho creato un package ma credo che basti altrimenti diventa tutto troppo frammentato. Se decidessi di cambiare DB basterebbe creare una nuova classe ed editare sopra le 6 query, non sarebbe un lavoro faticoso. Grazie ugualmente del consiglio.

    C.Perché "System.out" non va bene? Cosa offre di più un logger?
  • Re: Lavorare sulle basi dati con JDBC

    giannino1995 ha scritto:


    1.La mia intenzione era evitare che il codice si bloccasse ma in effetti se qualcosa non funziona la webapp va bloccata. Penserò a questo aspetto quando ritorno alla webapp.
    Se c'è un SQLException non lo devi ignorare, in sostanza.

    giannino1995 ha scritto:


    2.Mi riferisco al fatto che se lancio un ps.setString() dopo un PreparedStatement senza aprire un nuovo Try commetto un errore. Inoltre tutti questi finaly non mi piacciano, rendono il codice difficile da leggere. La tua soluzione è validissima, non travisare le mie parole ma preferisco avere un unico finaly nel codice.
    Fai pure. Ma devi farlo correttamente. Quello che avevi fatto all'inizio, non lo era.

    giannino1995 ha scritto:


    quando tento di mettere un record che poi non può essere inserito per un motivo o per l’altro nel DB viene perso un id come quando scrivo un record e poi lo cancello.
    Purtroppo con le sequence è così. Il DBMS "stacca" il numero dalla sequence poco prima di fare la insert. Se la insert fallisce, ormai il numero è stato staccato. Neanche se la insert fosse in un contesto transazionale, se a seguito di un errore si fa un rollback, questo non ha effetto sulla sequence. Detto in altro modo, la sequence non torna mai indietro, non "recupera" alcun valore.

    Generalmente questo non ha molta importanza, si accetta/trascura. Certo, se il tuo codice o la base dati non sono corretti e capita che hai 100 insert consecutive che falliscono, è un problema. Ma non della sequence. Del tuo codice e/o base dati che vanno sistemati.

    giannino1995 ha scritto:


    4.Nel codice trovi due nuovi metodi:
    isAcceptable(): è una classe aggiunta a DBMSUtente.java per verificare che la user e la password non siano nulle o contengano degli spazi oppure ancora prive di caratteri.
    La "validazione" dell'input è una cosa che si fa solitamente ad un livello superiore rispetto al DAO. NON la fa generalmente il DAO.

    giannino1995 ha scritto:


    5.Bellezza, grazia ed eleganza a parte la mia classe può andare oppure a tuo avviso ha gravi problemi di funzionalità e sicurezza?
    E continui a restituire null se la lista è vuota. Una lista vuota non ti piace proprio??

    E se continui a fare return qualcosa; nei catch, le eccezioni NON escono più dai metodi!! Cosa NON ti piace del far uscire fuori le eccezioni??

    Long numRighe = Long.valueOf(ps.executeUpdate());
    if(numRighe!=0){

    Ma che senso ha? executeUpdate() da un int. Tu lo incapsuli in un Long (oggetto) e poi nel test numRighe!=0 viene fatto un unboxing a long (primitivo) e lo 0 (int) portato (dal compilatore) a long per il confronto. Ma ragioni su queste cose basilari di Java??


    Se continui a ragionare (male) così e a cambiare le carte in tavola ogni volta ... questa "esercitazione" mi sa che non la finirai mai ....
  • Re: Lavorare sulle basi dati con JDBC

    C.Perché "System.out" non va bene? Cosa offre di più un logger?
    Per dir la verita', poco di piu' :

    - si possono abilitare/disabilitare, a livello di singolo log, di classe, di package, di intera applicazione, di PARTE dell'applicazione
    - si puo' decidere se visualizzare i log a livello di DEBUG/INFO/WARNING/ERROR/FATAL_ERROR (<LEVEL>)
    - si possono scrivere su console, su file, inviarli su database, via mail, via sms,, via TCP/IP
    - possono essere intercettati via browser, applicazione stand alone
    - possono essere analizzati, aggregati, filtrati
    - ed infinite altre cose ...

    e TUTTO QUESTO mentre l'applicazione e' in esecuzione, SENZA TOCCARE una riga di codice, e, OVVIAMENTE, senza fermare l'applicazione

    Ci si possono scrivere LIBRI su come si puo' usare un logger in modo intelligente.

    Ed il tutto con, fondamentamente, DUE righe di codice:
    
    Logger logger = Logger.getLogger(<LOGGER_NAME>); // crea il "logger"
    ...
    logger.log(<LEVEL>,<MESSAGE>); // usa il logger
    
    Ma QUESTA, e' un'altra storia
  • Re: Lavorare sulle basi dati con JDBC

    @giannino, SEGUI le indicazoni che ti vengono date.

    NON partire dall'idea: l'ho pensato io, quindi VA BENE anche se non e' perfetto

    OGNI consiglio che ti viene dato e' frutto DI STUDIO e DI ESPERIENZA PRATICA.
    Anche noi abbiamo fatto, prima o poi, le tue stesse scelte, con conseguenze DISASTROSE.
    OVVIAMENTE i disastri dovevano essere risolti e le soluzioni sono state ESATTAMENTE quello che ti viene consigliato.

    Quindi, NON CHIEDERE solo "perche' di questo, perche' di quello", ma RAGIONA sul PERCHE' NON VA BENE il tuo approccio e COSA HA DI MEGLIO il consiglio che ti viene dato. E se non ti viene in testa, STUDIA!

    Per fare un esempio:

    una query ritorna una LISTA di risultati.

    Se NON CI SONO RISULTATI e' meglio un "null" oppure una LISTA VUOTA?

    1) QUI' entrano in gioco concetti di algebra astratta: CHE COSA E' l'elemento Neutro?, e' quell'oggetto che, usato con un'operazione, non fa cambiare il risultato. Una lista vuota e' L'ELEMENTO NEUTRO per le cose che hanno a che fare con le liste.

    2) se devo scrivere del codice per scandire la lista, con il TUO approccio DEVO controllare se la lista e' "null", in vece con la lista vuota, il codice NON CAMBIA se devo scandire una lista di 1 elemeto, UN MILIONE o ZERO!

    3) questi sono i SOLI motivi? OVVIAMENTE NO!! Su questa SEMPLICE soluzione ci si puo' disquisire per una settimana!

    E c'e' il FONDAMENTALE ASSIOMA che ogni programmatore deve perseguire: MENO CODICE ---> MENO ERRORI

    Il massimo, per un VERO programmatore, e' quando riesce a DIMEZZARE il codice RADOPPIANDONE le funzionalita'

    Si puo' fare? Si fa, si fa!!!!!!!

    Sta' PROPRIO QUI' la bravura
  • Re: Lavorare sulle basi dati con JDBC

    X Andbin
    1.Scrivi che con le sequence è così ma c’è un altro metodo che non usa le sequence? Me lo illustri? Mi conviene impiegare quello? Il rollback() si può usare quando non c’è una sequence?
    2.Ho corretto il codice ma continuo a non capire perché fornire null sia sbagliato e sia preferibile la lista vuota.
    3.Si hai ragione, se disgraziatamente il codice del catch non funzionasse non uscirei più dal metodo. Meglio mettere throw new RuntimeException(e) e buona notte al secchio.
    4.Ok per i long, hai ragione ho fatto una sciocchezza.
    5.Una cosa così può andare oppure no?
    6.isAcceptable() mi piace che resti nel package DBMS perché definisce la logica del DB ma ritornando alla webapp se sento il bisogno eventualmente lo sposto. In effetti se il nome contiene " " non è logico scomodare il package DBMS ma fare tutto nella webapp.
    
    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 {
            Connection c = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            try {
                c = DBMSConnessione.connect();
                ps = c.prepareStatement("SELECT * FROM utenti");
                rs = ps.executeQuery();
                List<DBMSUtente> lista = new ArrayList<DBMSUtente>();
                while (rs.next()) {
                    DBMSUtente utente = new DBMSUtente();
                    utente.setId(rs.getLong("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;
            } catch (Exception e) {
                System.out.println("Non è stato possibile recuperare i record dalla tabella.");
                throw new RuntimeException(e);
            } finally {
                DBMSConnessione.close(rs , ps , c);
            }
        }
        public DBMSUtente findByNome(String nome) throws SQLException {
            Connection c = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            try {
                c = DBMSConnessione.connect();
                ps = c.prepareStatement("SELECT * FROM utenti WHERE nome = ?");
                ps.setString(1, nome);
                rs = ps.executeQuery();
                if (rs.next()) {
                    DBMSUtente utente = new DBMSUtente();
                    utente.setId(rs.getLong("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 = new DBMSUtente();
                    System.out.println("Non è stato possibile trovare il record.");
                    return utente;
                }
            } catch (Exception e) {
                System.out.println("Non è stato possibile recuperare il record dalla tabella.");
                throw new RuntimeException(e);
            } finally {
                DBMSConnessione.close(rs , ps , c);
            }
        }
        public DBMSUtente findById(Long id) throws SQLException {
            Connection c = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            try {
                c = DBMSConnessione.connect();
                ps = c.prepareStatement("SELECT * FROM utenti WHERE id = ?");
                ps.setLong(1, id);
                rs = ps.executeQuery();
                if (rs.next()) {
                    DBMSUtente utente = new DBMSUtente();
                    utente.setId(rs.getLong("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 = new DBMSUtente();
                    System.out.println("Non è stato possibile trovare il record.");
                    return utente;
                }
            } catch (Exception e) {
                System.out.println("Non è stato possibile recuperare il record dalla tabella.");
                throw new RuntimeException(e);
            } finally {
                DBMSConnessione.close(rs , ps , c);
            }
        }
        public Long insert(DBMSUtente u) throws SQLException {
            Connection c = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            try {
                if(!u.isAcceptable()) {
                    System.out.println("Non è stato possibile inserire il record.");
                    return 0L;
                }
                c = DBMSConnessione.connect();
                ps = c.prepareStatement("INSERT INTO utenti (nome, password) VALUES (? , ?)");
                ps.setString(1, u.getNome());
                ps.setString(2, u.getPassword());
                ps.executeUpdate(ps.toString(), PreparedStatement.RETURN_GENERATED_KEYS);
                rs = ps.getGeneratedKeys();
                Long idRiga = 0L;
                if (rs.next()) {
                    idRiga = rs.getLong(1);
                    System.out.println("E' stato possibile inserire il record nell'id: " + idRiga);
                }
                return idRiga;
            } catch (Exception e) {
                System.out.println("Non è stato possibile inserire il record.");
                return 0L;
            } finally {
                DBMSConnessione.close(rs , ps , c);
            }
        }
        public boolean update(DBMSUtente u) throws SQLException {
            Connection c = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            try {
                if(!u.isAcceptable()) {
                    System.out.println("Non è stato possibile inserire il record.");
                    return false;
                }
                c = DBMSConnessione.connect();
                ps = c.prepareStatement("UPDATE utenti SET nome = ?, password = ? WHERE id = ?");
                ps.setString(1, u.getNome());
                ps.setString(2, u.getPassword());
                ps.setLong(3, u.getId());
                int numRighe = ps.executeUpdate();
                if(numRighe!=0){
                    System.out.println("E' stato aggiornato il record.");
                    return true;
                }else{
                    System.out.println("Record non trovato.");
                    return false;
                }
            } catch (Exception e) {
                System.out.println("Non è stato possibile inserire il record.");
                return false;
            } finally {
                DBMSConnessione.close(rs , ps , c);
            }
        }
        public boolean delete(DBMSUtente u) throws SQLException {
            Connection c = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            try {
                c = DBMSConnessione.connect();
                ps = c.prepareStatement("DELETE FROM utenti WHERE id = ?");
                ps.setLong(1, u.getId());
                int numRighe = ps.executeUpdate();
                if(numRighe!=0){
                    System.out.println("E' stato cancellato il record.");
                    return true;
                }else{
                    System.out.println("Record non trovato.");
                    return false;
                }
            } catch (Exception e) {
                System.out.println("Non è stato possibile cancellare il record.");
                return false;
            } finally {
                DBMSConnessione.close(rs , ps , c);
            }
        }
    }
                                                                                                                                                                                                                                                                                
    
    X migliorabile
    Per quanto riguarda i logger forse può interessarmi la disabilitazione a livello di package ma solo se potessi con un’unica variabile o con un’unica riga di codice scegliere se stampare tutto sulla shell oppure niente, come si fa a fare questo?
    Quando l’applicazione è online i logger non solo non mi interessano ma meglio che nessuno li intercetti.
    Mi mostri come fare?
  • Re: Lavorare sulle basi dati con JDBC

    @giannino, per fortuna che sei "ziovine", perche' per un'affermazione come questa verresti IMMEDIATAMENTE DEFENESTRATO
    Ma dal 123-mo piano
    E non ti verrebbe nemmeno data l'ultima sigaretta!

    Tu NON HAI IDEA dell'IMPORTANZA dei log in QUALUNQUE tipo di applicazione MINIMAMENTE seria.
  • Re: Lavorare sulle basi dati con JDBC

    Quindi sto scrivendo stupidaggini su stupidaggini…
    Spiega meglio il discorso dei log per favore.
    Grazie per il tuo aiuto
  • Re: Lavorare sulle basi dati con JDBC

    giannino1995 ha scritto:


    1.Scrivi che con le sequence è così ma c’è un altro metodo che non usa le sequence? Me lo illustri?
    L'unico che ora, in questo momento, mi viene in mente è prendere il max+1. Ma dovrei andare a rileggermi da qualche parte se/quali implicazioni ci potrebbero essere.

    Ma comunque non capisco la tua preoccupazione, riferita ANCHE soprattutto a questa tua "esercitazione" che stai facendo. Le sequence vanno assolutamente BENE per quello che stai facendo ora. E comunque sappi che a livello "reale" è tipico mettere gli ID nelle tabelle come tipo bigint (64 bit).
    Se da una sequence stacchi 1000000000 (un MILIARDO!) di valori al GIORNO, prima di esaurire il bigint ci vorrebbero 25 e rotti MILIONI di ANNI (e non la sto sparando, è calcolato). Quindi, di COSA ti preoccupi??

    giannino1995 ha scritto:


    Mi conviene impiegare quello? Il rollback() si può usare quando non c’è una sequence?
    Prima di tutto: sai cosa è una transazione?? Sai cosa fanno un commit e un rollback?

    giannino1995 ha scritto:


    2.Ho corretto il codice ma continuo a non capire perché fornire null sia sbagliato e sia preferibile la lista vuota.
    Un null non è di per sé "sbagliato" in senso assoluto ma è SCOMODO. Perché il chiamante deve sempre fare un test, specialmente se ad esempio vuole usare il "for-each" di Java 5+ o vuole fare ordinamenti o altro.

    giannino1995 ha scritto:


    3.Si hai ragione, se disgraziatamente il codice del catch non funzionasse non uscirei più dal metodo.
    Ma che stai dicendo .... fai uscire quei SQLException !!

    giannino1995 ha scritto:


    Meglio mettere throw new RuntimeException(e) e buona notte al secchio.
    RuntimeException direttamente no. Come minimo sarebbe meglio fare una estensione es. DatabaseException.

    giannino1995 ha scritto:


    5.Una cosa così può andare oppure no?
    Lanci fuori RuntimeException ma continui ad avere i throws SQLException. Senti, deciditi .....

    E findByNome/findById l'avevo già detto PRIMA: NON va bene che restituisci un DBMSUtente "vuoto" (con valori default). Qui va BENE un null.

    Continui ad avere gli isAcceptable. Te l'ho già detto: la validazione dell'input "non dovrebbe" farla il DAO.

    E perché insert restituisce Long (oggetto!) ? Basta long primitivo. Perché continui a confondere long e Long ?

    giannino1995 ha scritto:


    Per quanto riguarda i logger forse può interessarmi la disabilitazione a livello di package ma solo se potessi con un’unica variabile o con un’unica riga di codice scegliere se stampare tutto sulla shell oppure niente, come si fa a fare questo?
    Come si fa? Dovresti STUDIARE le librerie di logging (es. log4j). Ma prima per cortesia, termina questa esercitazione ...
  • Re: Lavorare sulle basi dati con JDBC

    Ok mi accontento delle sequence.
    Si, so cosa è roolback, serve per editare contemporaneamente due tabelle. Per fare una cosa di questo genere:
    
    Connection c = null; 
     Statement s=null; 
     try {
       c=DriverManager.getConnection(url, user, passwd);
       c.setAutoCommit(false);
       try {
         s = c.createStatement();
         s.executeUpdate(...);
         s.executeUpdate(...);
         c.commit();
       } catch (Exception e) {
         c.rollback();
         throw e;
       }
     } finally {
       try {if(s!=null) s.close();} catch (Exception e) {...} 
       try {if(c!=null) c.close();} catch (Exception e) {...}
     }
    
    Nella mia esercitazione non serve a nulla. Credo serva per DBMS di ecommerce.
    NULL in findById e findByNome inserito.
    Long sostituito con long. Si in effetti basta il tipo primitivo.
    Ok, al momento lascio perdere i logger.
    isAcceptable() rimosso ma non cancellato, lo inserirò nella webapp prima di lanciare le query come da tuo consiglio.
    Ho tolto throws SQLException. Non ho capito il discorso dell'estensione, sembra una cosa complicata. Queste eccezioni proprio non le digerisco...
    Il codice seguente, a tuo avviso, ora può essere ritenuto accettabile?
    
    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() {
            Connection c = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            try {
                c = DBMSConnessione.connect();
                ps = c.prepareStatement("SELECT * FROM utenti");
                rs = ps.executeQuery();
                List<DBMSUtente> lista = new ArrayList<DBMSUtente>();
                while (rs.next()) {
                    DBMSUtente utente = new DBMSUtente();
                    utente.setId(rs.getLong("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;
            } catch (Exception e) {
                System.out.println("Non è stato possibile recuperare i record dalla tabella.");
                throw new RuntimeException(e);
            } finally {
                DBMSConnessione.close(rs , ps , c);
            }
        }
        public DBMSUtente findByNome(String nome) {
            Connection c = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            try {
                c = DBMSConnessione.connect();
                ps = c.prepareStatement("SELECT * FROM utenti WHERE nome = ?");
                ps.setString(1, nome);
                rs = ps.executeQuery();
                if (rs.next()) {
                    DBMSUtente utente = new DBMSUtente();
                    utente.setId(rs.getLong("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;
                }
            } catch (Exception e) {
                System.out.println("Non è stato possibile recuperare il record dalla tabella.");
                throw new RuntimeException(e);
            } finally {
                DBMSConnessione.close(rs , ps , c);
            }
        }
        public DBMSUtente findById(long id) {
            Connection c = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            try {
                c = DBMSConnessione.connect();
                ps = c.prepareStatement("SELECT * FROM utenti WHERE id = ?");
                ps.setLong(1, id);
                rs = ps.executeQuery();
                if (rs.next()) {
                    DBMSUtente utente = new DBMSUtente();
                    utente.setId(rs.getLong("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;
                }
            } catch (Exception e) {
                System.out.println("Non è stato possibile recuperare il record dalla tabella.");
                throw new RuntimeException(e);
            } finally {
                DBMSConnessione.close(rs , ps , c);
            }
        }
        public long insert(DBMSUtente u) {
            Connection c = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            try {
                c = DBMSConnessione.connect();
                ps = c.prepareStatement("INSERT INTO utenti (nome, password) VALUES (? , ?)");
                ps.setString(1, u.getNome());
                ps.setString(2, u.getPassword());
                ps.executeUpdate(ps.toString(), PreparedStatement.RETURN_GENERATED_KEYS);
                rs = ps.getGeneratedKeys();
                long idRiga = 0L;
                if (rs.next()) {
                    idRiga = rs.getLong(1);
                    System.out.println("E' stato possibile inserire il record nell'id: " + idRiga);
                }
                return idRiga;
            } catch (Exception e) {
                System.out.println("Non è stato possibile inserire il record.");
                return 0L;
            } finally {
                DBMSConnessione.close(rs , ps , c);
            }
        }
        public boolean update(DBMSUtente u) {
            Connection c = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            try {
                c = DBMSConnessione.connect();
                ps = c.prepareStatement("UPDATE utenti SET nome = ?, password = ? WHERE id = ?");
                ps.setString(1, u.getNome());
                ps.setString(2, u.getPassword());
                ps.setLong(3, u.getId());
                int numRighe = ps.executeUpdate();
                if(numRighe!=0){
                    System.out.println("E' stato aggiornato il record.");
                    return true;
                }else{
                    System.out.println("Record non trovato.");
                    return false;
                }
            } catch (Exception e) {
                System.out.println("Non è stato possibile inserire il record.");
                return false;
            } finally {
                DBMSConnessione.close(rs , ps , c);
            }
        }
        public boolean delete(DBMSUtente u) {
            Connection c = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            try {
                c = DBMSConnessione.connect();
                ps = c.prepareStatement("DELETE FROM utenti WHERE id = ?");
                ps.setLong(1, u.getId());
                int numRighe = ps.executeUpdate();
                if(numRighe!=0){
                    System.out.println("E' stato cancellato il record.");
                    return true;
                }else{
                    System.out.println("Record non trovato.");
                    return false;
                }
            } catch (Exception e) {
                System.out.println("Non è stato possibile cancellare il record.");
                return false;
            } finally {
                DBMSConnessione.close(rs , ps , c);
            }
        }
    }
    
    Grazie infinite
  • Re: Lavorare sulle basi dati con JDBC

    giannino1995 ha scritto:


    Si, so cosa è roolback, serve per editare contemporaneamente due tabelle.
    Eh? No, così l'hai detto in maniera molto impropria.

    Una transazione è una sequenza di N (2 o più) operazioni che devono essere trattate come una singola unità "atomica" di lavoro. O tutte hanno successo o nessuna deve essere applicata.
    Se tutte hanno successo, fai un commit per rendere persistenti tutte le modifiche. Se una fallisce, fai un rollback sostanzialmente per annullare le eventuali operazioni precedenti che hanno avuto successo.
    Lo ripeto, il senso del "atomico" è semplice: o tutto o niente!

    giannino1995 ha scritto:


    Per fare una cosa di questo genere:
    Sì la forma/struttura in generale è quella.

    giannino1995 ha scritto:


    Nella mia esercitazione non serve a nulla.
    Sì quasi sicuramente è cosi, dopotutto hai "solo" 2 tabelle e hai messo il ON DELETE CASCADE che già "aiuta" in tal senso.

    giannino1995 ha scritto:


    Credo serva per DBMS di ecommerce.
    Sì ecommerce ok, ma non c'entra solo quello, vale in GENERALE.

    Banalmente, se non avessi messo il ON DELETE CASCADE, per eliminare utente E suoi spostamenti, sarebbe necessario/giusto fare i due delete in una transazione.

    giannino1995 ha scritto:


    Non ho capito il discorso dell'estensione, sembra una cosa complicata.
    Se non sai estendere la classe di una eccezione, è una cosa parecchio grave e "seria". E dovrebbe forse farti riflettere e ragionare su quanto invece dovresti/dovrai (ancora) (RI)STUDIARE.
  • Re: Lavorare sulle basi dati con JDBC

    Mi sembra di ricordare che un'eccezione si estenda in questo modo:
    public static void main(String[] args) throws EccezioneDBMS {
            try {
                int a = 2;
                int b = 0;
                int c = a/b;
            } catch(Exception e) {
                throw new EccezioneDBMS("Non è stato possibile recuperare i record dalla tabella.");
            }
    }
    package DBMS;
    public class EccezioneDBMS extends Exception {
        private String dettagli;
        EccezioneDBMS(String testo) {
            dettagli = testo;
        }
        public String toString() {
            return "EccezioneDBMS: [" + dettagli + "]";
        }
    }
    E' questo che hai in mente?
  • Re: Lavorare sulle basi dati con JDBC

    giannino1995 ha scritto:


    Mi sembra di ricordare che un'eccezione si estenda in questo modo:
    Ti "sembra di ricordare"?? Queste sono cose che dovresti già sapere e a "menadito", come si dice ....

    giannino1995 ha scritto:


    E' questo che hai in mente?
    Primo, se estendi Exception rendi la tua eccezione "checked" (simile a SQLException nel senso che la devi dichiarare ovunque debba poter "uscire" da un metodo).
    Secondo, quel "dettagli" non serve a nulla, le eccezioni hanno già un "buon" toString().
    Terzo, se andassi a vedere il javadoc di Exception o RuntimeException, vedi che ci sono 4 forme (dei costruttori) base: senza argomenti, solo con message, message+cause, solo cause. Generalmente basta mettere una o più di queste forme che invocano il super-costruttore pari-pari. E basta.
    E nel tuo caso è sicuramente utile la forma message+cause.
  • Re: Lavorare sulle basi dati con JDBC

    Troppo complicato e perdo troppo tempo, lascio tutto così per ora altrimenti la mia esercitazione la finisco tra 30 anni.
    Grazie di tutto
  • Re: Lavorare sulle basi dati con JDBC

    giannino1995 ha scritto:


    Troppo complicato
    Questo è quanto si può fare:
    public class DatabaseException extends RuntimeException {
        public DatabaseException(String message, Throwable cause) {
            super(message, cause);
        }
    
        public DatabaseException(String message) {
            super(message);
        }
    
        public DatabaseException(Throwable cause) {
            super(cause);
        }
    }
    Poi nei metodi dao es.:
    } catch (SQLException e) {
        // eventuale logging se vuoi ...
        throw new DatabaseException("Errore nel findAll blablabla", e);      // <--- nota: passa ANCHE l'eccezione SQLException come "causa" interna
    }
    Ti sembra complicato? Ti rendi conto della gravità del non saper fare/usare una classe con 3 costruttori in croce?? (che tra l'altro li faccio quasi sempre generare da Eclipse, quindi ci metto 30 secondi neanche a fare una classe del genere).

    giannino1995 ha scritto:


    e perdo troppo tempo, lascio tutto così per ora altrimenti la mia esercitazione la finisco tra 30 anni.
    Hai perso molto tempo perché a) non hai basi valide e b) non ascolti quanto ti viene detto ...
    Comunque sì, concordo, finisci questa esercitazione.
  • Re: Lavorare sulle basi dati con JDBC

    Si, così, in effetti è molto meglio.
    Grazie mille
Devi accedere o registrarti per scrivere nel forum
105 risposte