JDBC에서 DATETIME 값 0000-00-00 00:00:00 처리


85

시도하면 예외가 발생합니다 (아래 참조).

resultset.getString("add_date");

DATETIME 값 0000-00-00 00:00:00 (DATETIME의 준 널 값)을 포함하는 MySQL 데이터베이스에 대한 JDBC 연결의 경우 값을 문자열이 아닌 문자열로 가져 오려고하지만 목적.

나는 이것을 통해 이것을 극복했다.

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 값은 적절한 유형의 "0"값 ( '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)

답변:


85

나는 동일한 문제를 해결하려는 시도를 우연히 발견했습니다. 내가 작업중인 설치는 JBOSS와 Hibernate를 사용하기 때문에 다른 방식으로해야했습니다. 기본적인 zeroDateTimeBehavior=convertToNull경우이 구성 속성 페이지 에 따라 연결 URI 에 추가 할 수 있어야 합니다 .

나는 당신의 최대 절전 모드 구성에 해당 매개 변수를 넣는 것과 관련하여 땅에서 다른 제안을 찾았습니다.

있는 hibernate.cfg.xml :

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

hibernate.properties :

hibernate.connection.zeroDateTimeBehavior=convertToNull

하지만 JBOSS의 mysql-ds.xml 파일에 다음 과 같이 넣어야했습니다 .

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

이것이 누군가를 돕기를 바랍니다. :)


상의 변화하고 있는 hibernate.cfg.xml의 내가 자바 거의 제로 지식을 가지고 있기 때문에, 나를 위해 트릭을 할 파일은, 감사합니다
Gendrith

124

대안으로, 데이터 소스 구성에서 직접이 JDBC URL을 사용할 수 있습니다.

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

편집하다:

출처 : MySQL 매뉴얼

구성 요소가 모두 0 인 날짜 시간 (0000-00-00 ...) —이 값은 Java에서 안정적으로 표현할 수 없습니다. Connector / J 3.0.x는 ResultSet에서 읽을 때 항상 NULL로 변환했습니다.

Connector / J 3.1은 JDBC 및 SQL 표준에 따라 가장 올바른 동작이므로 이러한 값이 발생하면 기본적으로 예외가 발생합니다. 이 동작은 zeroDateTimeBehavior 구성 속성을 사용하여 수정할 수 있습니다. 허용되는 값은 다음과 같습니다.

  • exception (기본값), SQLState가 S1009 인 SQLException이 발생합니다.
  • convertToNull , 날짜 대신 NULL을 반환합니다.
  • round , 가장 가까운 값인 0001-01-01로 날짜를 반올림합니다.

업데이트 : Alexander는 해당 기능에서 mysql-connector-5.1.15에 영향을 미치는 버그를보고했습니다. 공식 웹 사이트에서 CHANGELOGS를 참조하십시오 .


흥미 롭군요. 이 정보는 어디에서 찾았습니까?
Jason S

방금 내 대답을 업데이트했습니다! 그러나이 경우 @sarumont의 URL이 더 적합 할 수 있습니다 (모든 커넥터 속성을 나열합니다).
Brian Clozel 2010-04-22

1
jdbc 소프트웨어 버전 5.1.16에는 다음 버그 수정이 포함되어 있습니다.-BUG # 57808에 대한 수정-zeroDateTimeBehavior가 convertToNull이지만 getDate ()에서 값이 0000-00-00 인 DATE 필드에 대해 wasNull이 설정되지 않았습니다.
Alexander Kjäll 2011-06-15

와! 정보에 대해서 감사드립니다. 나는 당신이 그것을 알아내는 데 어려움을 겪었다 고 생각합니다 :-(
Brian Clozel 2011 년

URL .. 인생. 저장되었습니다!
CodingInCircles 2013-04-05

11

내 요점은 원시 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'을 "더미 날짜"로 저장할 수도 있습니다 (NO_ZERO_DATE SQL 모드를 사용하지 않는 경우). 이는 경우에 따라 NULL 값을 사용하는 것보다 더 편리합니다 (데이터와 인덱스 공간을 적게 사용함).

[..]

기본적으로 MySQL은 범위를 벗어난 날짜 또는 시간 유형에 대한 값을 발견하거나이 섹션의 시작 부분에 설명 된대로 유형에 대해 잘못된 값을 발견하면 해당 유형에 대한 값을 "0"값으로 변환합니다.


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

이를 사용하여 오류를 피하십시오. 날짜를 문자열 형식으로 반환 한 다음 문자열로 가져올 수 있습니다.

resultset.getString("dtime");

이것은 실제로 작동하지 않습니다. getString을 호출하더라도. 내부적으로 mysql은 여전히 ​​그것을 날짜로 먼저 변환하려고 시도합니다.

com.mysql.jdbc.ResultSetImpl.getDateFromString (ResultSetImpl.java:2270)에서

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

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

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


1
그것은 내 CAST (add_date AS CHAR) 솔루션과 다소 동일하지만 +1을 사용하면 원하는 방식으로 명시 적으로 형식을 지정할 수 있기 때문입니다.
Jason S

5

행을 추가 한 후 :

<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"));

5

나는이 문제와 씨름하고 위에서 논의한 'convertToNull'솔루션을 구현했습니다. 내 로컬 MySql 인스턴스에서 작동했습니다. 하지만 Play / Scala 앱을 Heroku에 배포하면 더 이상 작동하지 않습니다. Heroku는 또한 사용자에게 제공하는 DB URL과이 솔루션에 여러 인수를 연결합니다. 이는 Heroku가 "?"연결을 사용하기 때문입니다. 자신의 인수 세트 전에는 작동하지 않습니다. 그러나 똑같이 잘 작동하는 다른 솔루션을 찾았습니다.

SET sql_mode = 'NO_ZERO_DATE';

나는 이것을 내 테이블 설명에 넣고 '0000-00-00 00:00:00'이 java.sql.Timestamp로 표현 될 수 없다는 문제를 해결했습니다.


3

null 값을 나타내려면 null을 사용하는 것이 좋습니다.

당신이 얻는 예외는 무엇입니까?

BTW :

0 또는 0000이라는 연도는 없습니다. (일부 날짜는 올해 허용되지만)

그리고 한 해의 0 월이나 0 일이 없습니다. (문제의 원인이 될 수 있음)


예,하지만 소급 적으로도 0이라는 연도는 아직 없습니다. 1 AD / CE 이전 해는 1 BC / BCE
Peter Lawrey

2
이것이 기존 날짜와 충돌하지 않기 때문에 MySQL이 0000을 잘못된 날짜로 사용하는 전체 이유입니다. 또한 1999-00-00과 같은 날짜는 특정 날짜가 아닌 1999 년을 나타 내기 위해 때때로 사용됩니다 (내가 아님!).
Jason S

3

'00 -00 -.... '이 유효한 날짜가 아니라고 생각하는 문제를 해결 한 다음 "NULL"표현식을 추가하여 null 값을 허용하도록 SQL 열 정의를 변경했습니다.

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

마침내 모든 작업. 도움이 되었기를 바랍니다.


나는 이것이 모두 0의 MySQL DATETIME을 유효한 날짜로 변환하는 문제를 해결한다고 생각하지 않습니다. 실제로별로 도움이되지 않는 DATETIME 필드에 null을 입력하는 방법을 보여줍니다.
Mark Chorley 2013 년

2

다른 답변에 추가하려면 : 0000-00-00문자열을 원하지 않으면 다음을 사용할 수 있습니다.noDatetimeStringSync=true (시간대 변환을 희생한다는 경고와 함께) .

공식 MySQL 버그 : https://bugs.mysql.com/bug.php?id=47108 .

또한 히스토리의 경우 JDBC NULL0000-00-00날짜 를 반환 하는 데 사용 되었지만 이제는 기본적으로 예외를 반환합니다. 출처


2

jdbc URL을 추가 할 수 있습니다.

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

이를 통해 SQL은 '0000-00-00 00:00:00'을 null 값으로 변환합니다.

예 :

jdbc:mysql:<host-name>/<db-name>?zeroDateTimeBehavior=convertToNull&autoReconnect=true&characterEncoding=UTF-8&characterSetResults=UTF-8
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.