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 NULL는 0000-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.