обработка значений даты и времени 0000-00-00 00: 00: 00 в JDBC


Я получаю исключение (см. ниже), если я пытаюсь сделать

resultset.getString("add_date");

для соединения JDBC с базой данных MySQL, содержащей значение DATETIME 0000-00-00 00: 00: 00 (квази-нулевое значение для DATETIME), хотя я просто пытаюсь получить значение как строку, а не как объект.

Я обошел это, сделав

SELECT CAST(add_date AS CHAR) as add_date

который работает, но выглядит глупо... есть ли лучший способ сделать это?

моя точка зрения заключается в том, что я просто хочу необработанную строку DATETIME, так что я могу разобрать его сам как.

Примечание: вот где 0000 приходит в: (от http://dev.mysql.com/doc/refman/5.0/en/datetime.html)

незаконные дата-время, дата или метка времени значения преобразуются в "ноль" значение соответствующего типа ('0000-00-00 00:00:00' или '0000-00-00').

специфическое исключение это одно:

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)
10 80

10 ответов:

я наткнулся на эту попытку решить ту же проблему. Установка, с которой я работаю, использует JBOSS и Hibernate, поэтому мне пришлось сделать это по-другому. Для основного случая, вы должны быть в состоянии добавить zeroDateTimeBehavior=convertToNull к вашему URI соединения согласно этому настройки свойств страницы.

Я нашел другие предложения по всей стране, относящиеся к помещению этого параметра в ваш Hibernate config:

In спящий режим.контекстно-свободная грамматика.xml:

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

на спящий режим.свойства:

hibernate.connection.zeroDateTimeBehavior=convertToNull

но я должен был положить его в мой mysql-ds.xml файл для JBOSS как:

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

надеюсь, это кому-то поможет. :)

альтернативный ответ, вы можете использовать этот URL JDBC непосредственно в конфигурации источника данных:

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

Edit:

источник: MySQL Manual

даты со всеми нулевыми компонентами (0000-00-00 ...)- Эти значения не могут быть надежно представлены в Java. Разъем / J 3.0.x всегда преобразовывал их в NULL при чтении из результирующего набора.

Connector / J 3.1 создает исключение по умолчанию, когда эти значения встречается как это наиболее правильное поведение в соответствии со стандартами JDBC и SQL. Это поведение можно изменить с помощью свойства конфигурации zeroDateTimeBehavior. Допустимые значения:

  • исключение (по умолчанию), который вызывает SQLException с SQLState S1009.
  • convertToNull, который возвращает NULL вместо даты.
  • круглые, который округляет дату ближайшее значение, которое 0001-01-01.

обновление: Александр сообщил об ошибке, влияющей на mysql-connector-5.1.15 на этой функции. Смотрите изменения на официальном сайте.

моя точка зрения заключается в том, что я просто хочу необработанную строку DATETIME, поэтому я могу разобрать ее сам, как есть.

это заставляет меня думать, что ваш "обходной путь" не является обходным путем, но на самом деле единственный способ получить значение из базы данных в ваш код:

SELECT CAST(add_date AS CHAR) as add_date

кстати, еще несколько заметок из документации MySQL:

MySQL ограничения на недопустимые данные:

перед MySQL 5.0.2, MySQL прощает незаконные или неправильные значения данных и принуждает их к законным значениям для ввода данных. В MySQL 5.0.2 и выше это остается поведением по умолчанию, но вы можете изменить режим SQL сервера, чтобы выбрать более традиционную обработку плохих значений таким образом, что сервер отклоняет их и прерывает оператор, в котором они происходят.

[..]

при попытке сохранить значение NULL в столбце, который не принимает значения NULL, возникает ошибка для однорядных инструкций INSERT. Для нескольких строк Вставить операторы или для вставки В... Выберите инструкции, сервер MySQL хранит неявное значение по умолчанию для типа данных столбца.

MySQL 5.x типы даты и времени:

MySQL также позволяет хранить '0000-00-00' в качестве "фиктивной даты" (если вы не используете режим NO_ZERO_DATE SQL). Это в некоторых случаях более удобно (и использует меньше пространства данных и индексов), чем использование нулевых значений.

[..]

By по умолчанию, когда MySQL встречает значение для типа даты или времени, который находится вне диапазона или иным образом запрещен для типа (как описано в начале этого раздела), он преобразует значение в "нулевое" значение для этого типа.

DATE_FORMAT(column name, '%Y-%m-%d %T') as dtime

использовать это, чтобы избежать ошибки. Он возвращает дату в строковом формате, а затем вы можете получить его в виде строки.

resultset.getString("dtime");

это на самом деле не работает. Даже если вы вызываете getString. Внутренне mysql все еще пытается преобразовать его в дату сначала.

на com.mysql.интерфейс jdbc.Результаты неутешительны.getDateFromString(ResultSetImpl.java: 2270)

~[mysql-connector-java-5.1.15.банки:НС] в com.mysql.интерфейс jdbc.Результаты неутешительны.getStringInternal(ResultSetImpl.java: 5743)

~[mysql-connector-java-5.1.15.банки:НС] на ком.mysql.интерфейс jdbc.Результаты неутешительны.getString (ResultSetImpl.java: 5576)

~[mysql-connector-java-5.1.15.банки:НС]

если, после добавления строки:

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

hibernate.connection.zeroDateTimeBehavior=convertToNull

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

продолжает быть ошибка:

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

находим строчки:

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

заменить соответственно следующими строками:

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

Я боролся с этой проблемой и реализовал решения "convertToNull", рассмотренные выше. Он работал в моем локальном экземпляре MySql. Но когда я развернул свое приложение Play / Scala в Heroku, оно больше не будет работать. Heroku также объединяет несколько args в URL-адрес БД, который они предоставляют пользователям, и это решение, из-за использования Heroku конкатенации "?"прежде чем их собственный набор аргументов, не будет работать. Однако я нашел другое решение, которое, кажется, работает одинаково хорошо.

SET sql_mode = 'NO_ZERO_DATE';

Я поместил это в свои описания таблиц, и это решило проблему "0000-00-00 00:00:00" не может быть представлено как java.язык SQL.Метка времени

Я предлагаю вам использовать null для представления нулевого значения.

какое исключение вы получаете?

кстати:

год не называется 0 или 0000. (Хотя некоторые даты позволяют в этом году)

и нет никакого 0 месяца года или 0 дня месяца. (Что может быть причиной вашей проблемы)

Я решил проблему, учитывая '00-00-....'не является допустимой датой, тогда я изменил определение столбца SQL, добавив выражение "NULL", чтобы разрешить значения 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),...

затем я должен иметь возможность вставлять нулевые значения, что означает "я еще не зарегистрировал эту метку времени"...

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

таблица выглядит так:

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)

наконец: JPA в действии:

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

наконец - то вся его работа. Я надеюсь, что это поможет вам.

чтобы добавить к другим ответам: Если вы хотите 0000-00-00 строку, вы можете использовать noDatetimeStringSync=true (С оговоркой о жертвах преобразования часового пояса).

официальная ошибка MySQL:https://bugs.mysql.com/bug.php?id=47108.

кроме того, для истории, JDBC используется для возврата NULL на 0000-00-00 даты, но теперь возвращают исключение по умолчанию. источник

вы можете добавить url jdbc с

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

С помощью этого sql преобразует '0000-00-00 00:00:00' в нулевое значение.

например:

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