JDBC में DATETIME मानों को 0000-00-00 00:00:00 संभालना


85

अगर मुझे करने की कोशिश की जाए तो मुझे एक अपवाद मिलता है (नीचे देखें)

resultset.getString("add_date");

MySQL डेटाबेस के लिए JDBC कनेक्शन के लिए 0000-00-00 00:00:00 (DATETIME के ​​लिए अर्ध-शून्य मान) के DATETIME मान वाले, भले ही मैं स्ट्रिंग के रूप में मान प्राप्त करने की कोशिश कर रहा हूं, लेकिन नहीं वस्तु।

मैं यह कर के आसपास हो गया

SELECT CAST(add_date AS CHAR) as add_date

जो काम करता है, लेकिन मूर्खतापूर्ण लगता है ... क्या ऐसा करने का एक बेहतर तरीका है?

मेरा कहना है कि मैं सिर्फ कच्चा डैटटाइम स्ट्रिंग चाहता हूं, इसलिए मैं इसे खुद के रूप में पार्स कर सकता हूं ।

नोट: यहां 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)

जवाबों:


85

मैं एक ही मुद्दे को हल करने के प्रयास में ठोकर खा गया। मैं जिस इंस्टॉलेशन के साथ काम कर रहा हूं वह JBOSS और हाइबरनेट का उपयोग करता है, इसलिए मुझे यह एक अलग तरीके से करना पड़ा। मूल मामले के लिए, आपको zeroDateTimeBehavior=convertToNullइस कॉन्फ़िगरेशन गुण पृष्ठ के अनुसार अपने कनेक्शन URI में जोड़ने में सक्षम होना चाहिए ।

मुझे उस पैरामीटर को आपके हाइबरनेट कॉन्फ़िगरेशन में डालने के संदर्भ में भूमि के अन्य सुझाव मिले:

में hibernate.cfg.xml :

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

सीतनिद्रा में होना :

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 मैनुअल

सभी-शून्य घटकों (0000-00-00 ...) के साथ डेटासेट - ये मान जावा में मज़बूती से नहीं दिखाए जा सकते हैं। कनेक्टर / जे 3.0.x ने उन्हें हमेशा परिणाम के रूप में पढ़े जाने पर उन्हें NULL में बदल दिया।

कनेक्टर / J 3.1 इन मूल्यों का सामना करने पर डिफ़ॉल्ट रूप से एक अपवाद फेंकता है क्योंकि यह JDBC और SQL मानकों के अनुसार सबसे सही व्यवहार है। इस व्यवहार को शून्यडेट टाइमबेयर कॉन्फ़िगरेशन गुण का उपयोग करके संशोधित किया जा सकता है। स्वीकार्य मूल्य हैं:

  • अपवाद (डिफ़ॉल्ट), जो S1009 के SQLState के साथ एक SQLException फेंकता है।
  • ConvertToNull , जो दिनांक के बजाय NULL देता है।
  • राउंड , जो निकटतम निकटतम मान के लिए दिनांक है जो 0001-01-01 है।

अद्यतन: अलेक्जेंडर ने उस सुविधा पर mysql-कनेक्टर-5.1.15 को प्रभावित करने वाले एक बग की सूचना दी। आधिकारिक वेबसाइट पर CHANGELOGS देखें ।


दिलचस्प। आपको यह जानकारी कहां मिलेगी?
जेसन एस

बस मेरे उत्तर को अपडेट किया! लेकिन @sarumont का URL इस मामले में बेहतर हो सकता है (यह सभी कनेक्टर गुणों को सूचीबद्ध करता है)।
ब्रायन क्लोजेल

1
संस्करण 5.1.16 में jdbc सॉफ़्टवेयर में यह बगफिक्स शामिल है: - BUG # 57808 के लिए फिक्स - GetDate में मान 0000-00-00 के साथ DATE फ़ील्ड के लिए सेट नहीं किया गया है (हालांकि) zeroDateTimeBevivior ConvertToNull है।
अलेक्जेंडर केजेल

वाह! जानकारी के लिए धन्यवाद। मुझे लगता है कि आपके पास एक कठिन समय था जो पता लगा रहा था :-(
ब्रायन क्लोजेल

URL .. जीवन। बचाया!
CodingInCircles

11

मेरा कहना है कि मैं सिर्फ कच्चा डैटटाइम स्ट्रिंग चाहता हूं, इसलिए मैं इसे खुद के रूप में पार्स कर सकता हूं।

इससे मुझे लगता है कि आपका "वर्कअराउंड" वर्कअराउंड नहीं है, बल्कि वास्तव में आपके कोड के डेटाबेस से मूल्य प्राप्त करने का एकमात्र तरीका है:

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 के लिए ... चयनित कथन, MySQL सर्वर कॉलम डेटा प्रकार के लिए अंतर्निहित डिफ़ॉल्ट मान संग्रहीत करता है।

MySQL 5.x दिनांक और समय प्रकार :

MySQL आपको '0000-00-00' को "डमी तिथि" के रूप में संग्रहीत करने की अनुमति देता है (यदि आप NO_ZERO_DATE SQL मोड का उपयोग नहीं कर रहे हैं)। यह कुछ मामलों में NULL मानों का उपयोग करने की तुलना में अधिक सुविधाजनक (और कम डेटा और इंडेक्स स्पेस का उपयोग करता है) है।

[..]

डिफ़ॉल्ट रूप से, जब MySQL एक ऐसी तिथि या समय प्रकार के लिए एक मान का सामना करता है जो सीमा से बाहर है या अन्यथा प्रकार के लिए अवैध है (जैसा कि इस खंड की शुरुआत में वर्णित है), यह मान को उस प्रकार के लिए "शून्य" मान में परिवर्तित करता है।


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-कनेक्टर-java-5.1.15.jar: na] com.mysql.jdbc.ResultSetImpl.getStringInternal (ResultSetImpl.java:5743) पर

~ [mysql-कनेक्टर-java-5.1.15.jar: na] com.mysql.jdbc.ResultSetImpl.getString (ResultSetImpl.java:5576) पर

~ [Mysql-कनेक्टर-जावा-5.1.15.jar: na]


1
यह मेरे CAST (add_date AS CHAR) समाधान के समान है, लेकिन +1 चूंकि यह आपको स्पष्ट रूप से आपके इच्छित स्वरूप को प्रारूपित करने देता है।
जेसन एस

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 पर तैनात किया तो यह काम नहीं करेगा। हरोकू डीबी यूआरएल को कई तर्क देता है कि वे उपयोगकर्ताओं को प्रदान करते हैं, और यह समाधान, हर्को के उपयोग के कारण "?" आर्ग्स के अपने सेट से पहले, काम नहीं करेगा। हालांकि मुझे एक अलग समाधान मिला जो समान रूप से अच्छी तरह से काम करता है।

SET sql_mode = 'NO_ZERO_DATE';

मैंने इसे अपनी तालिका के विवरणों में रखा और इसने '0000-00-00 00:00:00' की समस्या को हल किया, इसे java.sql.Timestamp के रूप में प्रस्तुत नहीं किया जा सकता है


3

मेरा सुझाव है कि आप अशक्त मान का प्रतिनिधित्व करने के लिए अशक्त का उपयोग करें।

आपको क्या अपवाद मिलेगा?

Btw:

कोई वर्ष नहीं है जिसे 0 या 0000 कहा जाता है। (हालांकि कुछ तिथियां इस वर्ष की अनुमति देती हैं)

और साल का कोई ० महीना या महीने का ० दिन नहीं है। (जो आपकी समस्या का कारण हो सकता है)


हां, लेकिन अभी भी 0 नामक कोई वर्ष नहीं है, यहां तक ​​कि पूर्वव्यापी भी। 1 AD / CE से पहले का वर्ष 1 BC / BCE था
पीटर लॉरी

2
यही कारण है कि MySQL एक अवैध तारीख के रूप में 0000 का उपयोग करता है, क्योंकि यह मौजूदा तिथियों के साथ संघर्ष नहीं करता है। इसके अलावा, 1999-00-00 जैसी तारीखों का उपयोग कभी-कभी एक विशिष्ट दिन के बजाय वर्ष 1999 का प्रतिनिधित्व करने के लिए किया जाता है (मेरे द्वारा नहीं!)।
जेसन एस

3

मैंने '00 -00 'पर विचार करते हुए समस्या को हल कर दिया, -एक वैध तिथि नहीं है, फिर, मैंने अशक्त मानों को अनुमति देने के लिए "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();
    }

अंत में अपने सभी काम। मुझे उम्मीद है कि आपकी मदद करेंगे।


मुझे नहीं लगता कि यह सभी शून्य के MySQL DATETIME को एक वैध तिथि में परिवर्तित करने की समस्या को संबोधित करता है। यह सिर्फ दिखाता है कि कैसे एक DATETIME क्षेत्र में नल दर्ज करें जो वास्तव में बहुत मदद करने वाला नहीं है।
मार्क चोरले

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' को शून्य मान के रूप में परिवर्तित करता है।

उदाहरण के लिए:

jdbc:mysql:<host-name>/<db-name>?zeroDateTimeBehavior=convertToNull&autoReconnect=true&characterEncoding=UTF-8&characterSetResults=UTF-8
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.