handling DATETIME values 0000-00-00 00:00:00 in JDBC

前端 未结 10 1644
一向
一向 2020-11-27 11:01

I get an exception (see below) if I try to do

resultset.getString(\"add_date\");

for a JDBC connection to a MySQL database containing a DA

相关标签:
10条回答
  • 2020-11-27 11:04

    I solved the problem considerating '00-00-....' isn't a valid date, then, I changed my SQL column definition adding "NULL" expresion to permit null values:

    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),...
    

    Then, I've to be able to insert NULL values, that means "I didnt register that timestamp yet"...

    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),...
    

    The table look that:

    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)
    

    Finally: JPA in action:

    @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();
        }
    

    At last all its work. I hope that help you.

    0 讨论(0)
  • 2020-11-27 11:04

    you can append the jdbc url with

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

    With the help of this, sql convert '0000-00-00 00:00:00' as null value.

    eg:

    jdbc:mysql:<host-name>/<db-name>?zeroDateTimeBehavior=convertToNull&autoReconnect=true&characterEncoding=UTF-8&characterSetResults=UTF-8
    
    0 讨论(0)
  • 2020-11-27 11:08

    I wrestled with this problem and implemented the 'convertToNull' solutions discussed above. It worked in my local MySql instance. But when I deployed my Play/Scala app to Heroku it no longer would work. Heroku also concatenates several args to the DB URL that they provide users, and this solution, because of Heroku's use concatenation of "?" before their own set of args, will not work. However I found a different solution which seems to work equally well.

    SET sql_mode = 'NO_ZERO_DATE';

    I put this in my table descriptions and it solved the problem of '0000-00-00 00:00:00' can not be represented as java.sql.Timestamp

    0 讨论(0)
  • 2020-11-27 11:12

    To add to the other answers: If yout want the 0000-00-00 string, you can use noDatetimeStringSync=true (with the caveat of sacrificing timezone conversion).

    The official MySQL bug: https://bugs.mysql.com/bug.php?id=47108.

    Also, for history, JDBC used to return NULL for 0000-00-00 dates but now return an exception by default. Source

    0 讨论(0)
  • 2020-11-27 11:16

    My point is that I just want the raw DATETIME string, so I can parse it myself as is.

    That makes me think that your "workaround" is not a workaround, but in fact the only way to get the value from the database into your code:

    SELECT CAST(add_date AS CHAR) as add_date
    

    By the way, some more notes from the MySQL documentation:

    MySQL Constraints on Invalid Data:

    Before MySQL 5.0.2, MySQL is forgiving of illegal or improper data values and coerces them to legal values for data entry. In MySQL 5.0.2 and up, that remains the default behavior, but you can change the server SQL mode to select more traditional treatment of bad values such that the server rejects them and aborts the statement in which they occur.

    [..]

    If you try to store NULL into a column that doesn't take NULL values, an error occurs for single-row INSERT statements. For multiple-row INSERT statements or for INSERT INTO ... SELECT statements, MySQL Server stores the implicit default value for the column data type.

    MySQL 5.x Date and Time Types:

    MySQL also allows you to store '0000-00-00' as a “dummy date” (if you are not using the NO_ZERO_DATE SQL mode). This is in some cases more convenient (and uses less data and index space) than using NULL values.

    [..]

    By default, when MySQL encounters a value for a date or time type that is out of range or otherwise illegal for the type (as described at the beginning of this section), it converts the value to the “zero” value for that type.

    0 讨论(0)
  • 2020-11-27 11:18

    Alternative answer, you can use this JDBC URL directly in your datasource configuration:

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

    Edit:

    Source: MySQL Manual

    Datetimes with all-zero components (0000-00-00 ...) — These values can not be represented reliably in Java. Connector/J 3.0.x always converted them to NULL when being read from a ResultSet.

    Connector/J 3.1 throws an exception by default when these values are encountered as this is the most correct behavior according to the JDBC and SQL standards. This behavior can be modified using the zeroDateTimeBehavior configuration property. The allowable values are:

    • exception (the default), which throws an SQLException with an SQLState of S1009.
    • convertToNull, which returns NULL instead of the date.
    • round, which rounds the date to the nearest closest value which is 0001-01-01.

    Update: Alexander reported a bug affecting mysql-connector-5.1.15 on that feature. See CHANGELOGS on the official website.

    0 讨论(0)
提交回复
热议问题