2012-04-03 12 views
10

के साथ LOB स्ट्रिंग प्रॉपर्टी में यूरो-साइन स्टोर नहीं कर सकता है मुझे पोस्टग्रेएसक्यूएल 8.4 में लोब स्ट्रिंग गुणों में यूरो-साइन (€) जैसे विशेष वर्णों को लिखने और हाइबरनेट 3.6.10 के साथ पढ़ने में परेशानी हो रही है।हाइबरनेट/पोस्टग्रेएसक्यूएल

मुझे क्या पता है कि PostgreSQL तालिका के कॉलम में बड़ी वर्ण वस्तुओं को स्टोर करने के दो अलग-अलग तरीकों को प्रदान करता है। उन्हें सीधे उस तालिका कॉलम में या अप्रत्यक्ष रूप से एक अलग तालिका में संग्रहीत किया जा सकता है (इसे वास्तव में pg_largeobject कहा जाता है)। बाद के मामले में, स्तंभ में pg_largeobject में पंक्ति में संदर्भ (ओआईडी) होता है।

हाइबरनेट 3.6.10 में डिफ़ॉल्ट व्यवहार अप्रत्यक्ष ओआईडी दृष्टिकोण है। हालांकि, एक अतिरिक्त एनोटेशन @ org.hibernate.annotations जोड़ना संभव है। टाइप स्टोरेज व्यवहार प्राप्त करने के लिए लॉब प्रॉपर्टी में टाइप करें (टाइप = "org.hibernate.type.TextType")।

दोनों दृष्टिकोण ठीक काम करते हैं, इस पल को छोड़कर कि मैं यूरो चिह्न (€) जैसे विशेष पात्रों के साथ काम करना चाहता हूं। उस स्थिति में प्रत्यक्ष भंडारण तंत्र काम करता रहता है, लेकिन अप्रत्यक्ष भंडारण तंत्र टूट जाता है।

मैं एक उदाहरण के साथ प्रदर्शित करना चाहता हूं। मैंने 2 @ लॉब गुणों के साथ एक परीक्षण इकाई बनाई है। एक प्रत्यक्ष भंडारण सिद्धांत इस प्रकार है, अन्य अप्रत्यक्ष भंडारण:

@Basic 
@Lob 
@Column(name = "CLOB_VALUE_INDIRECT_STORAGE", length = 2147483647) 
public String getClobValueIndirectStorage() 

और

@Basic 
@Lob 
@org.hibernate.annotations.Type(type="org.hibernate.type.TextType") 
@Column(name = "CLOB_VALUE_DIRECT_STORAGE", length = 2147483647) 
public String getClobValueDirectStorage() 

अगर मैं एक इकाई बनाने के लिए, यूरो चिह्न के साथ दोनों के गुण को पॉप्युलेट और फिर डेटाबेस मैं देख रहा हूँ की ओर जारी रहती है निम्नलिखित मैं

id | clob_value_direct_storage | clob_value_indirect_storage 
----+---------------------------+---------------------------- 
    6 | €       | 910579      

देख मैं तो मेज pg_largeobject मैं देख रहा हूँ क्वेरी तो जब मैं एक का चयन करें:

loid | pageno | data 
--------+--------+------ 
910579 |  0 | \254 

pg_largeobject का 'डेटा' कॉलम बाइटा प्रकार का है, जिसका अर्थ है कि जानकारी कच्चे बाइट्स के रूप में संग्रहीत की जाती है। अभिव्यक्ति '\ 254' एक एकल बाइट का प्रतिनिधित्व करती है और यूटीएफ -8 में चरित्र '¬' का प्रतिनिधित्व करता है। यह वही मान है जो मैं वापस प्राप्त करता हूं जब मैं डेटाबेस से इकाई को वापस लोड करता हूं।

में यूरो चिह्न UTF-8 3 बाइट्स के होते हैं, तो मैं 'डेटा' स्तंभ की उम्मीद है 3 बाइट्स है और 1.

यह केवल, यूरो हस्ताक्षर के लिए नहीं होती है के लिए नहीं बल्कि करने के लिए होगा कई विशेष पात्र। क्या यह हाइबरनेट में एक समस्या है? या जेडीबीसी चालक? क्या कोई तरीका है कि मैं इस व्यवहार को बदल सकता हूं?

अग्रिम धन्यवाद,
सधन्यवाद,
फ़्रैंक डी Bruijn

+1

क्यों आप पहली जगह में बड़े वस्तुओं का उपयोग कर रहे हैं? बस उस कॉलम के लिए डेटाटाइप 'टेक्स्ट' का उपयोग करें। यदि आप स्टोर करना चाहते हैं तो 'बाइटा' या बड़ी वस्तुओं के साथ गड़बड़ करने की कोई आवश्यकता नहीं है। –

+0

ऐसा करने के कई कारण हो सकते हैं। मुझे नहीं पता। मैं अन्य उपयोगकर्ताओं के उपयोग के लिए एक ढांचा प्रदान करता हूं और मैं दोनों विकल्पों का समर्थन करना चाहता हूं। जेडीबीसी चालक के पुराने संस्करणों में (या हाइबरनेट, मुझे यकीन नहीं है) डिफ़ॉल्ट व्यवहार 'प्रत्यक्ष भंडारण' था। बाद में यह 'अप्रत्यक्ष भंडारण' में बदल गया। शायद कुछ अच्छे कारण के लिए। –

+0

मैंने इसके बारे में कुछ और सोचा और मैं वास्तव में a_horse_with_no_name के साथ अधिक से अधिक सहमत होना शुरू कर देता हूं। सबसे पहले अप्रत्यक्ष भंडारण तंत्र आपको इस कॉलम को एचक्यूएल क्वेरी में उपयोग करने से रोकता है, जो एक बड़ा नुकसान है। अप्रत्यक्ष भंडारण तंत्र स्ट्रीमिंग विकल्प की सुविधा प्रदान करता है, ताकि आप सीधे डेटाबेस से क्लाइंट (स्मृति उपयोग पर बचत) से सामग्री स्ट्रीम कर सकें। निश्चित रूप से यह बीएलओबी के लिए एक वैध तर्क है, लेकिन सीएलओबी के लिए? ज्यादातर परिदृश्यों में वास्तविक सीएलओबी का आकार उस बड़े, निश्चित रूप से 1 एम या उससे अधिक की सीमा में नहीं होगा। इसे स्मृति में संभाला जा सकता है। –

उत्तर

5

हाइबरनेट के स्रोत कोड और PostgreSQL JDBC ड्राइवर में चारों ओर खुदाई का एक बहुत बाद मैं समस्या के मूल कारणों का पता लगाने में कामयाब रहे। अंत में BlobOutputStream (जेडीबीसी चालक द्वारा प्रदान की गई) की लेखन() विधि को क्लोब की सामग्री को डेटाबेस में लिखने के लिए बुलाया जाता है। इस विधि इस प्रकार है:

public void write(int b) throws java.io.IOException 
{ 
    checkClosed(); 
    try 
    { 
     if (bpos >= bsize) 
     { 
      lo.write(buf); 
      bpos = 0; 
     } 
     buf[bpos++] = (byte)b; 
    } 
    catch (SQLException se) 
    { 
     throw new IOException(se.toString()); 
    } 
} 

इस विधि तर्क के रूप में एक 'int' (32 बिट/4 बाइट्स) लेता है और एक 'बाइट' (8 बिट/1 बाइट) को प्रभावी ढंग से जानकारी के 3 बाइट्स खोने में बदल देता है । जावा के भीतर स्ट्रिंग प्रस्तुतियां यूटीएफ -16 एन्कोडेड हैं, जिसका अर्थ है कि प्रत्येक चरित्र को 16 बिट्स/2 बाइट्स द्वारा दर्शाया जाता है। यूरो-साइन में int मान 8364 है। बाइट में रूपांतरण के बाद, मान 172 बनी हुई है (ऑक्टेट प्रतिनिधित्व 254 में)।

मुझे यकीन नहीं है कि अब इस समस्या का सबसे अच्छा समाधान क्या है। आईएमएचओ जेडीबीसी चालक जावा यूटीएफ -16 अक्षरों को एन्कोडिंग/डिकोडिंग के लिए ज़िम्मेदार होना चाहिए जो डाटाबेस की जरूरतों को एन्कोड करने के लिए आवश्यक है। हालांकि, मुझे अपने व्यवहार को बदलने के लिए जेडीबीसी ड्राइवर कोड में कोई ट्वीकिंग संभावनाएं नहीं दिख रही हैं (और मैं अपना खुद का जेडीबीसी ड्राइवर कोड लिखना और बनाए रखना नहीं चाहता)।

इसलिए, मैंने कस्टम क्लोब टाइप के साथ हाइबरनेट को बढ़ाया और यूटीएफ -16 अक्षरों को डेटाबेस में लिखने से पहले यूटीएफ -8 में परिवर्तित करने में कामयाब रहा और क्लाउब को पुनर्प्राप्त करते समय इसके विपरीत।

समाधान इस उत्तर में बस साधारण पेस्ट के लिए बहुत बड़ा है। यदि आप रुचि रखते हैं, तो मुझे एक लाइन छोड़ दो, और मैं इसे आपको भेजता हूं।

चीयर्स, फ़्रैंक

+0

फ्रैंक मैं अविश्वसनीय बड़े वर्चर (जो कि है) का उपयोग कर इसके आसपास मिल गया है पोस्टग्रेस टेक्स्ट कॉलम)। मुझे पता नहीं है कि यह आदर्श नहीं है क्योंकि वर्चर कॉलम शायद स्मृति में लोड हो रहा है (क्लॉब की जगह शायद बड़े होने पर डिस्क पर बफर किया जाता है) लेकिन यह काम करता है। –

+0

फ़्रैंक, 'BlobOutputStream.write (int b) का व्यवहार सही है। जो भी इसे बुला रहा है वह गलत तरीके से इसका उपयोग करने की संभावना है। [आउटपुटस्ट्रीम जावाडॉक] के अनुसार (http://docs.oracle.com/javase/6/docs/api/java/io/OutputStream.html#write (int)) * "लिखने के लिए सामान्य अनुबंध 'है एक बाइट आउटपुट स्ट्रीम में लिखा जाता है। बाइट को लिखा जाना चाहिए, तर्क के आठ कम ऑर्डर बिट्स बी हैं। बी के 24 उच्च ऑर्डर बिट्स को नजरअंदाज कर दिया जाता है। "* क्या आपके पास एक टेस्ट केस है जो इस मुद्दे को प्रदर्शित करता है? यदि ऐसा है, तो कृपया हाइबरनेट के खिलाफ एक बग फ़ाइल करें और यहां से लिंक करें। (मैं जेडीबीसी चालक पर मदद करता हूं) –

+0

यदि पोस्टग्रेएसक्यूएल चालक ने अभी तक एनसीएलओबी के लिए समर्थन लागू किया है तो शायद आप क्लोब के बजाय हाइबरनेट का उपयोग एनसीएलओब करने का प्रयास कर सकते हैं? वैसे भी हाइबरनेट में राष्ट्रीयकृत चरित्र समर्थन के लिए मेरी योजना थी: जेडीबीसी 4 (प्रकार। सीएलओबी, प्रकार। एनएचएआरए, प्रकार। एनएचकएआर, प्रकार। लोंगवर्चर) में परिभाषित राष्ट्रीयकृत रूपों का समर्थन करना। –