Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 11
  1. #1
    Utente di HTML.it
    Registrato dal
    Oct 2010
    Messaggi
    5

    [JAVA] SQLException: il campo non ha valore di default

    Ciao a tutti,
    sto scrivendo un programma che importando le informazioni da un file .txt esterno, li carichi in un database.

    Il file txt, molto lungo, è così composto (AnagraficaLibri.txt)

    codice:
    West side Transilvania#Marks John#E/O#2010
    Una faccenda privata#Iles Greg#Piemme#2010
    Il bizzarro museo degli orrori#Rhodes Dan#Newton Compton#2010
    L' amore del bandito letto da Rolando Ravello#Carlotto Massimo#Emons#2010
    Spelix. Storia di gatti# di stranieri e di un delitto#Rivera Annamaria#Dedalo#2010
    Jane e l'arcano di Penfolds Hall#Barron Stephanie#TEA#2010
    Hunted. La casa della notte#Cast P. C.; Cast Kristin#Nord#2010
    Gli illuminati#Bello Antoine#Fazi#2010
    Tredici ore#Meyer Deon#E/O#2010
    Praticamente: titolo#autore#casaEditrice#anno.

    Questi dati vanno caricati nel database LIBRERIA, nella tabella libro. Segue il codice sql.

    codice:
    create table if not exists libro (
    id_libro int auto_increment not null,
    titolo text not null,
    autore text not null,
    casaEditrice text not null,
    anno year not null,
    
    primary key (id_libro)
    ) engine=innodb;
    A questo punto mi sono creato un'applicazione JAVA per eseguire ciò che volevo:

    codice:
    import java.io.*;
    import java.sql.*;
    import java.util.*;
    
    
    	public class LetturaFile
    	{
    		public static void main(String[] args) throws Exception	{
    
    			try {   
    				Class.forName("com.mysql.jdbc.Driver");
    				Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/LIBRERIA?" + "user=user&password=xxx");
    				
    	        Statement stmt = conn.createStatement();
    			Scanner anagrafica = new Scanner(new File("AnagraficaLibri.txt"));
    			anagrafica.useDelimiter("/n");
    			
    			
    			while(anagrafica.hasNext()){
    				StringTokenizer split = new StringTokenizer(anagrafica.next(),"#");
    				while(split.hasMoreTokens()){
    				for(int i=1; i<=4; i++){
    					if (i==1){
    						String titolo = split.nextToken();
    						stmt.executeUpdate("INSERT INTO libro(titolo) VALUES ('"+titolo+"')");
    					} else if (i==2){
    						String autore = split.nextToken();
    						stmt.executeUpdate("INSERT INTO libro(autore) VALUES ('"+autore+"')");
    					} else if (i==3){
    						String casaEditrice = split.nextToken();
    						stmt.executeUpdate("INSERT INTO libro(casaEditrice) VALUES ('"+casaEditrice+"')");
    					} else if (i==4){
    						String anno = split.nextToken();
    						stmt.executeUpdate("INSERT INTO libro(anno) VALUES ('"+anno+"')");
    					}
    				}
    				
    				
    					
    				}
    				
    				stmt.close();
    				conn.close(); 
    				
    			}
    	       }
    	         catch(ClassNotFoundException e)
    	        {
    	            System.out.println(e);
    	        }
    	        catch(SQLException e)
    	        {
    	            System.out.println(e);
    	        }finally{
    	            System.out.println("Operazione effettuata.");
    			}
    		
    
    		}
    	}
    Ho utilizzato come delimitatore l'invio e come split il #. L'errore che mi stampa è: java.sql.SQLException: Field 'autore' doesn't have a default value, cioè "il campo autore non ha un valore di default", ed effettivamente così dovrebbe essere visto che i dati glieli sto passando io manualmente. Infine, mi sono accorto che non legge tutto il file ma si ferma ad un certo punto. Anche qui, non ho capito perchè.

    p.s. Abbiate pietà, ho ore di studio e lavoro alle spalle!

    Grazie in anticipo.

  2. #2
    Utente di HTML.it
    Registrato dal
    Aug 2002
    Messaggi
    8,013
    non ho letto tutto il codice, comunque subito all'occhio:

    codice:
    anagrafica.useDelimiter("/n");
    non è il delimitatore che ti aspetti tu: eventualmente
    codice:
    "\n"
    è il ritorno a capo.

    Non conosco Scanner, ma qui, dovendo leggere comunque riga per riga, ci darei di BufferedReader, eliminando fin da subito il primo problema di: quale sarà il corretto delimitatore per i diversi ambienti? (\r\n ? \n?)


    Poi il resto mi sembra oltremodo macchinoso: quanto meno, fai una insert per ogni riga... non 4 come adesso (e anche sulla insert per ogni riga ci si potrebbe discutere, ma per non sbattersi troppo per il momento diciamo che va bene così)
    <´¯)(¯`¤._)(¯`»ANDREA«´¯)(_.¤´¯)(¯`>
    "The answer to your question is: welcome to tomorrow"

  3. #3
    Utente di HTML.it
    Registrato dal
    Feb 2007
    Messaggi
    4,157
    a parte che non fai nessun controllo se la stringa è valida oppure meno (cosa che a me non piace perché consegnare un progetto così al cliente significa fargli vedere una SQLException e si mette paura, meglio un messaggio che dice dato non valido, scrivilo bene), penso che stai usando male java (cioè non stai sfruttando bene la programmazione ad oggetti, i bean e le feature che il linguaggio offre).

  4. #4
    Utente di HTML.it
    Registrato dal
    Aug 2002
    Messaggi
    8,013
    Oh, una cosa prima che ci sbatti contro con Statement... ti consiglio di usare PreparedStatement, che si occupa da sola di fare l'escape di eventuali caratteri "cattivi", tipo l'apice singolo.

    Riducendo all'osso il codice (ma come ha fatto notare valia, andrebbero effettuati controlli sulla consistenza dei dati), qualcosa del genere:
    codice:
    try {
                BufferedReader br = new BufferedReader(new FileReader("percorso/libreria.txt"));
                String entry = "";
                Statement stmt = conn.createStatement();
                PreparedStatement pstmt = conn.prepareStatement("INSERT into libro (titolo, autore, editore, anno) "
                        + "VALUES (?, ?, ?, ?)");
                while ((entry = br.readLine()) != null) {
                    String[] tokens = entry.split("#");                
                    for (int i = 0; i < tokens.length-1; i++) {
                        pstmt.setString((i+1), tokens[i]);
                    }
                    pstmt.setInt(4, Integer.parseInt(tokens[tokens.length-1]));
                    pstmt.execute();
                }
            }
            catch (Exception e) {
                e.printStackTrace();
            }
    <´¯)(¯`¤._)(¯`»ANDREA«´¯)(_.¤´¯)(¯`>
    "The answer to your question is: welcome to tomorrow"

  5. #5
    Utente di HTML.it
    Registrato dal
    Oct 2010
    Messaggi
    5
    Ringrazio entrambi! Ho modificato opportunamente e adesso sono riuscito a caricarmi il mio file. Passo a crearmi i metodi di controllo (grazie valia per il consiglio), connessione e disconnessione, che così non mi piace.

  6. #6
    Utente di HTML.it
    Registrato dal
    Feb 2007
    Messaggi
    4,157
    beh dovresti iniziare anche ad usare i bean (che tornano utili).

    @Andrea
    A me piace capire perché scelgo l'uso di uno strumento anziché di un altro.
    Ora lo Statament è la prima cosa che la libreria mette a disposizione, alla fine a te interessa eseguire una stringa sql well formed e quello lo Statement te lo fa fare.
    Il PreparedStatement l'ho sempre usato per questione di ottimizzazione (usare una query pre-compilata in alcuni casi mi ha aiutato come tempistiche e risorse utilizzate), mai come prassi normale di programmazione.
    Gli apici o comunque la corretta formattazione della stringa sql che esegui è preoccupazione del programmatore e devi avere chiaro il tutto indipendentemente se programmi in Java, C/C++, C#, se fai script in python, php, asp.
    Se ci pensi bene tu puoi eseguire una query direttamente sul db, copiare e incollare la stringa all'interno di un qualsiasi listato di codice e poter eseguire la stessa query.
    In C# se non ricordo male anteponendo @ alla stringa di dimentichi pure di escape e robe varie, quindi alla fine per capire il concetto io lo trovo migliore.
    Poi, avendo chiara la base, capisci che volendo puoi velocizzare le tue query (ma non so quanto sia necessario pre-compilare una query quando la usi una tantum) e allora passi al prepared. La scelta ovviamente di uno o dell'altro dipende da quello che devi fare, ma io terrei Statement come base e Prepared come eccezione

  7. #7
    Utente di HTML.it
    Registrato dal
    Aug 2002
    Messaggi
    8,013
    Non sono affatto d'accordo. Statement ti mette nella condizione di dover scrivere di tuo pugno ed ogni volta (con possibilità di errori dovuti ad inesperienza e imperizia) tutto quanto già scritto a livelli di API per quanto riguarda i problemi di SQL injection etc etc.
    E' un fatto di security: si usano le cose appropriate.

    Qui skud dovrebbe farsi l'escape degli apici a manina, e vabbhè, dirai, che ci vuole (sono d'accordo)... domani l'applicazione viene ricicciata, ci fanno un front-end per l'inserimento online dei dati, il core resta quello di ieri e nascono i problemi di sicurezza. Tanto vale cominciare subito bene.
    <´¯)(¯`¤._)(¯`»ANDREA«´¯)(_.¤´¯)(¯`>
    "The answer to your question is: welcome to tomorrow"

  8. #8
    Utente di HTML.it
    Registrato dal
    Feb 2007
    Messaggi
    4,157
    il problema è che per te cominciare bene è avere roba pre-compilata nel database engine sempre pronta (anche se non è detto che venga usata) tenuto conto che a volte è meglio scriverla a manina perché il database engine può ottimizzare anche lo Statement.

    per me si tratta di linee guida di programmazione, è vero che ti dà sicurezza, ma ripeto devi sapere fare la query scrivendola a manina, copiandola (facendo ovviamente attenzione) e poi eseguendola direttamente. Devi avere tu la tua sicurezza e non basarti esclusivamente su quella che ti fornisce una libreria (che a volte sbaglia).
    Devi sapere che ti servono i caratteri di escape, devi sapere come metterli perché se sai fare una query in java, devi saperla fare in C++. Può cambiare la sintassi dei comandi e le API che usi, ma in sostanza la query e il modo di scriverla non cambia. Se impari a fare questo, impari il concetto generale, capisci meglio quando ti serve usare una e l'altra.

    Riguardo a tutti i problemi di sicurezza, al momento direi di lasciarli stare, devi aggiungere una roba alla volta, non tutto insieme (che poi ti sembrano robe astruse).

    Ripeto, per la mia esperienza, prima è meglio concentrarsi sul problema, poi si passa a guardare le cose che in alcuni casi ci danno una maggiore "facilità" di scrittura.

    Riguardo le modifiche, se sai scrivere il tuo programma quelle saranno minime, il problema è sempre sapere quello che fai, come lo fai e soprattutto farlo con il minimo indispensabile (ti torna utile quando per qualche motivo, che adesso ti sembra impossibile, ti chiedono tagli e ottimizzazioni)

    Queste sono considerazioni nate dalla mia esperienza sul campo con i database e dalla mia esperienza come tutor (far capire il concetto e come funziona è più importante per me, ripeto alla fine sono sintassi che se capisci la logica sai usare)

    A tal proposito guarda pure il tutorial
    oracle


  9. #9
    Utente di HTML.it
    Registrato dal
    Oct 2010
    Messaggi
    5
    Interessante la discussione. Le FAQ Oracle comunque, se non ricordo male, incoraggiano più all'uso del PreparedStatement piuttosto che dello Statement, proprio per il discorso sicurezza ed evitare il binding.

    “Statements may be slightly faster if you are only going to execute the SQL once. PreparedStatements are much faster when the SQL will be executed more than once. If you are using the statement cache, which you should, getting a statement from the cache is the same as executing the same statement.

    In general we strongly recommend that you use PreparedStatements. This is especially true if you are sending user provided data in the SQL. By binding the data to a PreparedStatement parameter you can prevent most SQL injection attacks. Any performance advantage of using Statements is negligible.”
    Approfitto per porvi un'altra domanda: quali sono le differenze tra uno StringTokenizer ed uno split? Immagino lo split sia più performante, ma in quali casi è meglio usare l'uno e non l'altro?

  10. #10
    Moderatore di Programmazione L'avatar di LeleFT
    Registrato dal
    Jun 2003
    Messaggi
    17,328
    Originariamente inviato da skud
    Approfitto per porvi un'altra domanda: quali sono le differenze tra uno StringTokenizer ed uno split? Immagino lo split sia più performante, ma in quali casi è meglio usare l'uno e non l'altro?
    No, non mescolare più argomenti nella stessa discussione che diventa un macello. Apri una nuova discussione.

    Ciao.
    "Perchè spendere anche solo 5 dollari per un S.O., quando posso averne uno gratis e spendere quei 5 dollari per 5 bottiglie di birra?" [Jon "maddog" Hall]
    Fatti non foste a viver come bruti, ma per seguir virtute e canoscenza

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.