2012-07-19 14 views
7

हम एक यूटीएफ -16 एन्कोडेड स्ट्रिंग को AL32UTF8 ओरेकल डेटाबेस में स्टोर करने की कोशिश कर रहे हैं।ओरेकल जेडीबीसी वर्णसेट और 4000 चार सीमा

हमारा प्रोग्राम डेटाबेस पर पूरी तरह से काम करता है जो WE8MSWIN1252 को वर्णमाला के रूप में उपयोग करता है। जब हम इसे डेटाबेस पर चलाने का प्रयास करते हैं जो AL32UTF8 का उपयोग करता है तो यह java.sql.SQLException: ORA-01461: can bind a LONG value only for insert into a LONG column पर जाता है।

नीचे दिए गए टेस्टकेस में सब कुछ ठीक काम करता है जब तक कि हमारे इनपुट डेटा को बहुत लंबा नहीं मिलता है।

इनपुट स्ट्रिंग 4000 वर्णों से अधिक हो सकती है। हम जितना संभव हो उतना अधिक जानकारी बरकरार रखना चाहते हैं, भले ही हमें पता चले कि इनपुट को काटना होगा।

हमारे डेटाबेस टेबल CHAR कीवर्ड (नीचे देखें) का उपयोग करके परिभाषित किए गए हैं। हमें आशा थी कि इससे हमें किसी भी चरित्र सेट के 4000 वर्णों को स्टोर करने की अनुमति मिल जाएगी। क्या यह किया जा सकता है? यदि हां, तो कैसे?

हमने सफलता के बिना ByteBuffer का उपयोग करके स्ट्रिंग को UTF8 में परिवर्तित करने का प्रयास किया है। OraclePreparedStatement.setFormOfUse(...) ने भी हमारी मदद नहीं की।

CLOB पर स्विच करना एक विकल्प नहीं है। यदि स्ट्रिंग बहुत लंबी है तो इसे काटने की जरूरत है।

इस पल में हमारे कोड है:

public static void main(String[] args) throws Exception { 
    String ip ="193.53.40.229"; 
    int port = 1521; 
    String sid = "ora11"; 
    String username = "obasi"; 
    String password = "********"; 

    String driver = "oracle.jdbc.driver.OracleDriver"; 
    String url = "jdbc:oracle:thin:@" + ip + ":" + port + ":" + sid; 
    Class.forName(driver); 

    String shortData = ""; 
    String longData = ""; 
    String data; 

    for (int i = 0; i < 5; i++) 
     shortData += "é"; 

    for (int i = 0; i < 4000; i++) 
     longData += "é"; 

    Connection conn = DriverManager.getConnection(url, username, password); 

    PreparedStatement stat = null; 
    try { 
     stat = conn.prepareStatement("insert into test_table_short values (?)"); 
     data = shortData.substring(0, Math.min(5, shortData.length())); 
     stat.setString(1, data); 
     stat.execute(); 

     stat = conn.prepareStatement("insert into test_table_long values (?)"); 
     data = longData.substring(0, Math.min(4000, longData.length())); 
     stat.setString(1, data); 
     stat.execute(); 
    } finally { 
     try { 
      stat.close(); 
     } catch (Exception ex){} 
    } 
} 

यह सरल तालिका के स्क्रिप्ट बनाने है:

CREATE TABLE test_table_short (
    DATA VARCHAR2(5 CHAR); 
); 

CREATE TABLE test_table_long (
    DATA VARCHAR2(4000 CHAR); 
); 

परीक्षण का मामला कम डेटा पर पूरी तरह से काम करता है। लंबे डेटा पर हालांकि यह त्रुटि प्राप्त करता रहता है। यहां तक ​​कि जब हमारे longData केवल 3000 अक्षरों का लंबा होता है, तब भी यह सफलतापूर्वक निष्पादित नहीं होता है।

अग्रिम धन्यवाद!

उत्तर

7

ओरेकल 12.1 से पहले, VARCHAR2 कॉलम डेटाबेस वर्ण सेट में डेटा के 4000 बाइट्स को संग्रहीत करने तक ही सीमित है, भले ही इसे VARCHAR2(4000 CHAR) घोषित किया गया हो। चूंकि आपकी स्ट्रिंग में प्रत्येक वर्ण को यूटीएफ -8 वर्ण सेट में 2 बाइट स्टोरेज की आवश्यकता होती है, इसलिए आप कॉलम में 2000 से अधिक वर्णों को स्टोर नहीं कर पाएंगे। बेशक, यह संख्या बदलेगी यदि आपके कुछ पात्रों को वास्तव में केवल 1 बाइट स्टोरेज की आवश्यकता होती है या उनमें से कुछ को स्टोरेज के 2 बाइट से अधिक की आवश्यकता होती है। जब डेटाबेस वर्ण सेट Windows-1252 है, तो आपकी स्ट्रिंग में प्रत्येक वर्ण को केवल एक ही बाइट स्टोरेज की आवश्यकता होती है ताकि आप कॉलम में 4000 वर्णों को स्टोर कर सकें।

चूंकि आपके पास लंबे तार हैं, तो VARCHAR2 के बजाय कॉलम को CLOB के रूप में घोषित करना संभव होगा? वह (प्रभावी रूप से) लंबाई सीमा को हटा देगा (CLOB के आकार पर एक सीमा है जो ओरेकल संस्करण और ब्लॉक आकार पर निर्भर करती है लेकिन यह कम से कम कई जीबी रेंज में है)।

यदि आप ओरेकल 12.1 या बाद में उपयोग करते हैं, तो max_string_size पैरामीटर आपको increase the maximum size of a VARCHAR2 column from 4000 bytes to 32767 bytes पर अनुमति देता है।

+0

आपके उत्तर के लिए धन्यवाद। अफसोस की बात है, इस मामले में, क्लोब का उपयोग करना हमारे लिए सवाल से बाहर है। [लिंक] के अनुसार (https://forums.oracle.com/forums/thread.jspa?threadID=2369974) यह सही उत्तर है। हालांकि, [लिंक] (http://stackoverflow.com/questions/81448/difference-between-byte-and-char-in-column-datatypes) मेरे विनम्र विपक्ष में बहुत भ्रामक है। क्या आप जानते हैं कि दस्तावेज़ीकरण में यह कहां समझाया गया है? हम बहुत कुछ खोज रहे हैं, लेकिन यह नहीं मिला। – Arolition

+0

@Arolition - मैंने SO थ्रेड पर एक टिप्पणी जोड़ा। जवाब अब तक सही है। यह सिर्फ ध्यान नहीं देता है कि यदि किसी विशेष 4000 वर्णों को 4000 बाइट स्टोरेज की आवश्यकता होती है जो 4000 बाइट क्षमता सीमा अभी भी अंदर आती है। –

+1

यूटीएफ -8 एक चर लंबाई लंबाई एन्कोडिंग है। कई एशियाई पात्रों को कम से कम तीन बाइट एन्कोड करने की आवश्यकता होती है। –

4

स्ट्रिंग को बाइट लंबाई की आवश्यकता के द्वारा इस समस्या को हल किया।ध्यान दें कि यह बस

stat.substring(0, length) 

का उपयोग कर के बाद से यह एक UTF-8 स्ट्रिंग है कि लंबे समय तक की अनुमति दी तुलना में तीन गुना हो सकता है का उत्पादन द्वारा नहीं किया जा सकता है।

while (stat.getBytes("UTF8").length > length) { 
    stat = stat.substring(0, stat.length()-1); 
} 

टिप्पणी stat.getBytes() का उपयोग नहीं करते के बाद से इस सेट 'file.encoding' पर निर्भर है और या तो विंडोज़ -1252 या UTF-8 बाइट्स का उत्पादन!

यदि आप हाइबरनेट का उपयोग करते हैं तो आप org.hibernate.Interceptor का उपयोग करके ऐसा कर सकते हैं!

संबंधित मुद्दे