обработка значений DATETIME 0000-00-00 00:00:00 в JDBC - PullRequest
82 голосов
/ 23 апреля 2009

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

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)

Недопустимый DATETIME, DATE или TIMESTAMP значения конвертируются в «ноль» значение соответствующего типа ('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 ]

120 голосов
/ 13 апреля 2010

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

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

Edit:

Источник: MySQL Manual

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

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

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

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

81 голосов
/ 25 июля 2009

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

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

В hibernate.cfg.xml :

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

В hibernate.properties :

hibernate.connection.zeroDateTimeBehavior=convertToNull

Но мне пришлось поместить его в мой файл mysql-ds.xml для JBOSS как:

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

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

11 голосов
/ 24 апреля 2009

Суть в том, что мне просто нужна необработанная строка 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. Для многострочных операторов INSERT или для операторов INSERT INTO ... SELECT MySQL Server сохраняет неявное значение по умолчанию для типа данных столбца.

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

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

[..]

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

6 голосов
/ 12 августа 2009
DATE_FORMAT(column name, '%Y-%m-%d %T') as dtime

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

resultset.getString("dtime");

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

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

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

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

~ [MySQL-разъем-Java-5.1.15.jar: на]

5 голосов
/ 16 января 2013

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

SET sql_mode = 'NO_ZERO_DATE';

Я поместил это в описание моей таблицы, и это решило проблему '0000-00-00 00:00:00', которую нельзя представить как java.sql.Timestamp

5 голосов
/ 06 декабря 2011

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

<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"));
3 голосов
/ 19 мая 2013

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

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

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

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

3 голосов
/ 23 апреля 2009

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

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

Кстати:

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

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

2 голосов
/ 23 августа 2016

Вы можете добавить 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
2 голосов
/ 29 января 2016

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...