gestione valori DATETIME 0000-00-00 00:00:00 in JDBC

Ottengo un’eccezione (vedi sotto), se provo a fare

resultset.getString("add_date");

per una connessione JDBC per MySQL è un database che contiene un valore DATETIME di 0000-00-00 00:00:00 (il quasi nullo valore DATETIME), anche se sto solo cercando di ottenere il valore come stringa e non come un oggetto.

Ho ottenuto tutto questo facendo

SELECT CAST(add_date AS CHAR) as add_date

che funziona, ma sembra sciocco… c’è un modo migliore per fare questo?

Il mio punto è che io voglio solo il raw DATETIME stringa, in modo che in grado di analizzare me stesso come è.

nota: ecco dove l’0000 arriva: (da http://dev.mysql.com/doc/refman/5.0/en/datetime.html)

Illegale di data e ora, DATA, o TIMESTAMP
i valori vengono convertiti a “zero”
valore del tipo appropriato
(‘0000-00-00 00:00:00’ o
‘0000-00-00’).

L’eccezione specifica è questa:

SQLException: Cannot convert value '0000-00-00 00:00:00' from column 5 to TIMESTAMP.
SQLState: S1009
VendorError: 0
java.sql.SQLException: Cannot convert value '0000-00-00 00:00:00' from column 5 to TIMESTAMP.
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1055)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:926)
    at com.mysql.jdbc.ResultSetImpl.getTimestampFromString(ResultSetImpl.java:6343)
    at com.mysql.jdbc.ResultSetImpl.getStringInternal(ResultSetImpl.java:5670)
    at com.mysql.jdbc.ResultSetImpl.getString(ResultSetImpl.java:5491)
    at com.mysql.jdbc.ResultSetImpl.getString(ResultSetImpl.java:5531)
InformationsquelleAutor Jason S | 2009-04-23



10 Replies
  1. 81

    Mi sono imbattuto in questo tentativo di risolvere lo stesso problema. L’installazione sto lavorando con gli usi e Hibernate JBOSS, ho avuto modo di fare questo in un modo diverso. Per il caso base, si dovrebbe essere in grado di aggiungere zeroDateTimeBehavior=convertToNull per la connessione URI per questo pagina delle proprietà di configurazione.

    Ho trovato altri suggerimenti in tutto il paese, riferendosi a mettere che il parametro di sospensione config:

    In hibernate.cfg.xml:

    <property name="hibernate.connection.zeroDateTimeBehavior">convertToNull</property>

    In di sospensione.proprietà:

    hibernate.connection.zeroDateTimeBehavior=convertToNull

    Ma ho dovuto mettere nella mia mysql-ds.xml file per JBOSS as:

    <connection-property name="zeroDateTimeBehavior">convertToNull</connection-property>

    Spero che questo aiuta qualcuno. 🙂

  2. 122

    Risposta alternativa, è possibile utilizzare questo JDBC URL direttamente nella tua configurazione dell’origine dati:

    jdbc:mysql://yourserver:3306/yourdatabase?zeroDateTimeBehavior=convertToNull

    Edit:

    Fonte: MySQL Manuale

    Datetimes con tutti zero componenti (0000-00-00 …) — Questi valori non possono essere rappresentati in modo affidabile in Java. Connector/J 3.0.x sempre convertite a NULL quando viene letto da un gruppo di Risultati.

    Connector/J 3.1 genera un’eccezione per impostazione predefinita, quando questi valori vengono rilevati come questo è il più corretto comportamento secondo il JDBC e SQL standard. Questo comportamento può essere modificato utilizzando il zeroDateTimeBehavior proprietà di configurazione. I valori consentiti sono:

    • eccezione (impostazione predefinita), che getta una SQLException con un SQLState di S1009.
    • convertToNull, che restituisce NULL al posto della data.
    • giro, che completa la data più vicina, più vicina di valore che è 0001-01-01.

    Aggiornamento: Alexander segnalato un bug che interessa mysql-connector-5.1.15 tale caratteristica. Vedere CHANGELOG sul sito ufficiale.

    • interessante. dove hai fatto a trovare questa info?
    • appena aggiornato la mia risposta! Ma @sarumont ‘URL può andare meglio, in questo caso (elenca tutte le proprietà del connettore).
    • Fantastico!!! Grazie.
    • versione 5.1.16 di jdbc software contiene questo bugfix: – Fix per il BUG#57808 – wasNull non è impostato per il campo DATA con valore 0000-00-00 in getDate (), anche se zeroDateTimeBehavior è convertToNull.
    • Wow! Grazie per le info. Credo che hai avuto un momento difficile capire che fuori 🙁
    • grazie mille, questo mi ha salvato 🙂
    • L’URL.. la Vita. Salvata!

  3. 11

    Il mio punto è che io voglio solo il raw DATETIME stringa, in modo che in grado di analizzare me stesso come è.

    Che mi fa pensare che la tua “soluzione” non è una soluzione, ma in realtà l’unico modo per ottenere il valore dal database nel tuo codice:

    SELECT CAST(add_date AS CHAR) as add_date

    Tra l’altro, alcune più note della documentazione di MySQL:

    MySQL Vincoli Dati non validi:

    Prima di MySQL 5.0.2, MySQL è il perdono di illeciti o non corretti valori di dati e assegna loro i valori legali per l’immissione dei dati. In MySQL 5.0.2 e fino, che rimane il comportamento di default, ma è possibile modificare il server SQL modo per selezionare più di un trattamento tradizionale di bad valori in modo che il server li rifiuta e abbandona la dichiarazione in cui si verificano.

    [..]

    Se si tenta di memorizzare NULL in una colonna che non prende i valori NULL, si verifica un errore per singola riga di INSERT. Per l’INSERIMENTO di più righe di istruzioni o per INSERIRE IN … istruzioni SELECT, MySQL Server memorizza l’implicito valore predefinito per il tipo di dati della colonna.

    MySQL 5.x Tipi di data e Ora:

    MySQL consente inoltre di memorizzare ‘0000-00-00’ come un “dummy ” data” (se non si utilizza il NO_ZERO_DATE modalità SQL). Questo è, in alcuni casi, più conveniente (e utilizza meno di dati e di indice di spazio) rispetto all’utilizzo di valori NULL.

    [..]

    Per impostazione predefinita, quando MySQL rileva un valore per una data o un orario tipo che è fuori portata o altrimenti illegale, per il tipo (come descritto all’inizio di questa sezione), converte il valore per il valore “zero” per quel tipo.

    • Fantastico, grazie.
  4. 6
    DATE_FORMAT(column name, '%Y-%m-%d %T') as dtime

    Utilizzare questo per evitare l’errore. Restituisce la data in formato stringa e quindi si può ottenere come una stringa.

    resultset.getString("dtime");

    Questo in realtà NON funziona. Anche se si chiama il metodo getString. Internamente mysql ancora tenta di convertirlo alla data di prima.

    al com.mysql.jdbc.ResultSetImpl.getDateFromString(ResultSetImpl.java:2270)

    ~[mysql-connector-java-5.1.15.jar:na] a com.mysql.jdbc.ResultSetImpl.getStringInternal(ResultSetImpl.java:5743)

    ~[mysql-connector-java-5.1.15.jar:na] a com.mysql.jdbc.ResultSetImpl.getString(ResultSetImpl.java:5576)

    ~[mysql-connector-java-5.1.15.jar:na]

    • Che è un pò lo stesso come il mio CAST(add_date COME CHAR) soluzione, ma +1 poiché questo consente di formattare in modo esplicito il modo in cui si desidera.
  5. 5

    Se, dopo l’aggiunta di righe:

    <property
    name="hibernate.connection.zeroDateTimeBehavior">convertToNull</property>
    
    hibernate.connection.zeroDateTimeBehavior=convertToNull
    
    <connection-property
    name="zeroDateTimeBehavior">convertToNull</connection-property>

    continua ad essere un errore:

    Illegal DATETIME, DATE, or TIMESTAMP values are converted to the zero value of the appropriate type ('0000-00-00 00:00:00' or '0000-00-00').

    trovare linee:

    1) resultSet.getTime("time"); //time = 00:00:00
    2) resultSet.getTimestamp("timestamp"); //timestamp = 00000000000000
    3) resultSet.getDate("date"); //date = 0000-00-00 00:00:00

    sostituire con le seguenti righe, rispettivamente:

    1) Time.valueOf(resultSet.getString("time"));
    2) Timestamp.valueOf(resultSet.getString("timestamp"));
    3) Date.valueOf(resultSet.getString("date"));
  6. 5

    Ho lottato con questo problema e implementato il ‘convertToNull’ soluzioni discusse in precedenza. Ha funzionato nel mio locale MySql istanza. Ma quando ho sviluppato il mio stile di Gioco/Scala app per Heroku più non avrebbe funzionato. Heroku, inoltre, consente di concatenare diversi argomenti per il DB URL che offrono agli utenti, e questa soluzione, perché di Heroku uso concatenazione di”?”, prima di una propria serie di argomenti, non funziona. Tuttavia ho trovato una diversa soluzione che sembra funzionare altrettanto bene.

    SET sql_mode = ‘NO_ZERO_DATE’;

    Ho messo questo nella mia tabella descrizioni e risolto il problema del ‘0000-00-00 00:00:00’, non può essere rappresentato come java.sql.Timestamp

  7. 3

    Vi suggerisco di utilizzare null per rappresentare un valore null.

    Che cosa è l’eccezione che si ottiene?

    BTW:

    Non c’è l’anno chiamato 0 o 0000. (Anche se alcune date consentire di quest’anno)

    E c’è 0 mese dell’anno o 0 giorno del mese. (Che può essere la causa del tuo problema)

    • mai sentito parlare di sistemi legacy
    • sì, ma non c’è ancora l’anno chiamato 0, anche a posteriori. L’anno prima 1 ANNUNCI/CE è stato 1 BC/AC
    • Questo è il vero motivo MySQL utilizza 0000, come una data non valida, perché non è in conflitto con le attuali date. Inoltre, date come 1999-00-00 è talvolta usato (non da me!) per rappresentare l’anno 1999, piuttosto che un giorno specifico.
  8. 3

    Ho risolto il problema considerating ’00-00-….’ non è una data valida, quindi, ho cambiato il mio SQL per la definizione di colonna aggiunta di “NULL” expresion per consentire i valori null:

    SELECT "-- Tabla item_pedido";
    CREATE TABLE item_pedido (
        id INTEGER AUTO_INCREMENT PRIMARY KEY,
        id_pedido INTEGER,
        id_item_carta INTEGER,
        observacion VARCHAR(64),
        fecha_estimada TIMESTAMP,
        fecha_entrega TIMESTAMP NULL, //HERE IS!!.. NULL = DELIVERY DATE NOT SET YET
        CONSTRAINT fk_item_pedido_id_pedido FOREIGN KEY (id_pedido)
            REFERENCES pedido(id),...

    Poi, devo essere in grado di inserire i valori NULL, che significa “io non registrare che il timestamp di sicurezza”…

    SELECT "++ INSERT item_pedido";
    INSERT INTO item_pedido VALUES
    (01, 01, 01, 'Ninguna', ADDDATE(@HOY, INTERVAL 5 MINUTE), NULL),
    (02, 01, 02, 'Ninguna', ADDDATE(@HOY, INTERVAL 3 MINUTE), NULL),...

    Tabella look:

    mysql> select * from item_pedido;
    +----+-----------+---------------+-------------+---------------------+---------------------+
    | id | id_pedido | id_item_carta | observacion | fecha_estimada      | fecha_entrega       |
    +----+-----------+---------------+-------------+---------------------+---------------------+
    |  1 |         1 |             1 | Ninguna     | 2013-05-19 15:09:48 | NULL                |
    |  2 |         1 |             2 | Ninguna     | 2013-05-19 15:07:48 | NULL                |
    |  3 |         1 |             3 | Ninguna     | 2013-05-19 15:24:48 | NULL                |
    |  4 |         1 |             6 | Ninguna     | 2013-05-19 15:06:48 | NULL                |
    |  5 |         2 |             4 | Suave       | 2013-05-19 15:07:48 | 2013-05-19 15:09:48 |
    |  6 |         2 |             5 | Seco        | 2013-05-19 15:07:48 | 2013-05-19 15:12:48 |
    |  7 |         3 |             5 | Con Mayo    | 2013-05-19 14:54:48 | NULL                |
    |  8 |         3 |             6 | Bilz        | 2013-05-19 14:57:48 | NULL                |
    +----+-----------+---------------+-------------+---------------------+---------------------+
    8 rows in set (0.00 sec)

    Infine: l’APP in azione:

    @Stateless
    @LocalBean
    public class PedidosServices {
        @PersistenceContext(unitName="vagonpubPU")
        private EntityManager em;
    
        private Logger log = Logger.getLogger(PedidosServices.class.getName());
    
        @SuppressWarnings("unchecked")
        public List<ItemPedido> obtenerPedidosRetrasados() {
            log.info("Obteniendo listado de pedidos retrasados");
            Query qry = em.createQuery("SELECT ip FROM ItemPedido ip, Pedido p WHERE" +
                    " ip.fechaEntrega=NULL" +
                    " AND ip.idPedido=p.id" +
                    " AND ip.fechaEstimada < :arg3" +
                    " AND (p.idTipoEstado=:arg0 OR p.idTipoEstado=:arg1 OR p.idTipoEstado=:arg2)");
            qry.setParameter("arg0", Tipo.ESTADO_BOUCHER_ESPERA_PAGO);
            qry.setParameter("arg1", Tipo.ESTADO_BOUCHER_EN_SERVICIO);
            qry.setParameter("arg2", Tipo.ESTADO_BOUCHER_RECIBIDO);
            qry.setParameter("arg3", new Date());
    
            return qry.getResultList();
        }

    Finalmente tutto il suo lavoro. Spero che ti aiutano.

    • Non credo che questo risolve il problema della conversione di un MySQL DATETIME di zeri in una data valida. A dimostrazione di come inserire un valore null in un campo di tipo DATETIME che non è davvero intenzione di aiutare molto.
  9. 2

    Per aggiungere alle altre risposte: Se proprio vuoi il 0000-00-00 stringa, è possibile utilizzare noDatetimeStringSync=true (con l’avvertenza di sacrificare il fuso orario di conversione).

    Ufficiale di MySQL bug: https://bugs.mysql.com/bug.php?id=47108.

    Anche, per la storia, JDBC utilizzato per restituire NULL per 0000-00-00 date, ma ora restituire un’eccezione per impostazione predefinita.
    Fonte

  10. 2

    è possibile aggiungere l’url jdbc con

    ?zeroDateTimeBehavior=convertToNull&autoReconnect=true&characterEncoding=UTF-8&characterSetResults=UTF-8

    Con l’aiuto di questo, sql convert ‘0000-00-00 00:00:00’ come valore null.

    ad esempio:

    jdbc:mysql:<host-name>/<db-name>?zeroDateTimeBehavior=convertToNull&autoReconnect=true&characterEncoding=UTF-8&characterSetResults=UTF-8

Lascia un commento