Oracle
 sql >> डेटाबेस >  >> RDS >> Oracle

हाइबरनेट में Oracle XMLType कॉलम का उपयोग करना

मेरी दिशा और आवश्यकताएं

  • इकाई को एक्सएमएल को एक स्ट्रिंग (java.lang.String) के रूप में स्टोर करना चाहिए
  • डेटाबेस को XML को XDB.XMLType कॉलम में बना रहना चाहिए
    • अनुक्रमण और अधिक कुशल xpath/ExtractValue/xquery प्रकार की क्वेरी की अनुमति देता है
  • पिछले सप्ताह में मिले एक दर्जन या इतने ही आंशिक समाधानों को समेकित करें
  • कार्य वातावरण
    • Oracle 11g r2 x64
    • हाइबरनेट 4.1.x
    • जावा 1.7.x x64
    • विंडोज 7 प्रो x64

चरण-दर-चरण समाधान

चरण 1:xmlparserv2.jar (~1350kb) खोजें

यह जार चरण 2 को संकलित करने के लिए आवश्यक है, और यहां ऑरैकल इंस्टॉलेशन में शामिल है:%ORACLE_11G_HOME%/LIB/xmlparserv2.jar

चरण 1.5:xdb6.jar (~257kb) खोजें

यह महत्वपूर्ण है यदि आप Oracle 11gR2 11.2.0.2 या अधिक का उपयोग कर रहे हैं, या बाइनरी XML के रूप में संग्रहीत कर रहे हैं।

क्यों?

  • 11.2.0.2+ में XMLType कॉलम SECUREFILE BINARYXML का उपयोग करके संग्रहीत किया जाता है डिफ़ॉल्ट रूप से, जबकि पुराने संस्करणों को BASICFILECLOB . के रूप में संग्रहीत किया जाएगा
  • xdb*.jar के पुराने संस्करण बाइनरी एक्सएमएल को ठीक से डीकोड नहीं करते हैं और चुपचाप विफल हो जाते हैं
    • Google Oracle डेटाबेस 11g रिलीज़ 2 JDBC ड्राइवर और डाउनलोड करें xdb6.jar
  • बाइनरी एक्सएमएल डिकोडिंग समस्या का निदान और समाधान यहां बताया गया है

चरण 2:XMLType कॉलम के लिए एक हाइबरनेट UserType बनाएं

Oracle 11g और हाइबरनेट 4.x के साथ, यह जितना लगता है उससे कहीं अधिक आसान है।

public class HibernateXMLType implements UserType, Serializable {
static Logger logger = Logger.getLogger(HibernateXMLType.class);


private static final long serialVersionUID = 2308230823023l;
private static final Class returnedClass = String.class;
private static final int[] SQL_TYPES = new int[] { oracle.xdb.XMLType._SQL_TYPECODE };

@Override
public int[] sqlTypes() {
    return SQL_TYPES;
}

@Override
public Class returnedClass() {
    return returnedClass;
}

@Override
public boolean equals(Object x, Object y) throws HibernateException {
    if (x == null && y == null) return true;
    else if (x == null && y != null ) return false;
    else return x.equals(y);
}


@Override
public int hashCode(Object x) throws HibernateException {
    return x.hashCode();
}

@Override
public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException {

    XMLType xmlType = null;
    Document doc = null;
    String returnValue = null;
    try {
        //logger.debug("rs type: " + rs.getClass().getName() + ", value: " + rs.getObject(names[0]));
        xmlType = (XMLType) rs.getObject(names[0]);

        if (xmlType != null) {
            returnValue = xmlType.getStringVal();
        }
    } finally {
        if (null != xmlType) {
            xmlType.close();
        }
    }
    return returnValue;
}

@Override
public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException {

    if (logger.isTraceEnabled()) {
        logger.trace("  nullSafeSet: " + value + ", ps: " + st + ", index: " + index);
    }
    try {
        XMLType xmlType = null;
        if (value != null) {
            xmlType = XMLType.createXML(getOracleConnection(st.getConnection()), (String)value);
        }
        st.setObject(index, xmlType);
    } catch (Exception e) {
        throw new SQLException("Could not convert String to XML for storage: " + (String)value);
    }
}


@Override
public Object deepCopy(Object value) throws HibernateException {
    if (value == null) {
        return null;
    } else {
        return value;
    }
}

@Override
public boolean isMutable() {
    return false;
}

@Override
public Serializable disassemble(Object value) throws HibernateException {
    try {
        return (Serializable)value;
    } catch (Exception e) {
        throw new HibernateException("Could not disassemble Document to Serializable", e);
    }
}

@Override
public Object assemble(Serializable cached, Object owner) throws HibernateException {

    try {
        return (String)cached;
    } catch (Exception e) {
        throw new HibernateException("Could not assemble String to Document", e);
    }
}

@Override
public Object replace(Object original, Object target, Object owner) throws HibernateException {
    return original;
}



private OracleConnection getOracleConnection(Connection conn) throws SQLException {
    CLOB tempClob = null;
    CallableStatement stmt = null;
    try {
        stmt = conn.prepareCall("{ call DBMS_LOB.CREATETEMPORARY(?, TRUE)}");
        stmt.registerOutParameter(1, java.sql.Types.CLOB);
        stmt.execute();
        tempClob = (CLOB)stmt.getObject(1);
        return tempClob.getConnection();
    } finally {
        if ( stmt != null ) {
            try {
                stmt.close();
            } catch (Throwable e) {}
        }
    }
}   

चरण 3:अपनी इकाई में फ़ील्ड को एनोटेट करें।

मैं स्प्रिंग/हाइबरनेट के साथ एनोटेशन का उपयोग कर रहा हूं, फाइलों को मैप नहीं कर रहा हूं, लेकिन मुझे लगता है कि सिंटैक्स समान होगा।

@Type(type="your.custom.usertype.HibernateXMLType")
@Column(name="attribute_xml", columnDefinition="XDB.XMLTYPE")
private String attributeXml;

चरण 4:Oracle JAR के परिणामस्वरूप एपसर्वर/जूनिट त्रुटियों से निपटना

संकलन त्रुटियों को हल करने के लिए अपने क्लासपाथ में %ORACLE_11G_HOME%/LIB/xmlparserv2.jar (1350kb) शामिल करने के बाद, अब आपको अपने एप्लिकेशन सर्वर से रनटाइम त्रुटियां मिलती हैं...

http://www.springframework.org/schema/beans/spring-beans-3.1.xsd<Line 43, Column 57>: XML-24509: (Error) Duplicated definition for: 'identifiedType'
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd<Line 61, Column 28>: XML-24509: (Error) Duplicated definition for: 'beans'
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd<Line 168, Column 34>: XML-24509: (Error) Duplicated definition for: 'description'
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd<Line 180, Column 29>: XML-24509: (Error) Duplicated definition for: 'import'
... more ...

त्रुटियां क्यों?

Xmlparserv2.jar SAXParserFactory, DocumentBuilderFactory और TransformerFactory के लिए उपयोग की जाने वाली डिफ़ॉल्ट javax.xml कक्षाओं को बदलने के लिए JAR सेवा API (सेवा प्रदाता तंत्र) का उपयोग करता है।

यह कैसे हुआ?

javax.xml.parsers.FactoryFinder इस क्रम में, पर्यावरण चर, %JAVA_HOME%/lib/jaxp.properties, फिर META-INF/सेवाओं के अंतर्गत क्लासपाथ पर कॉन्फ़िग फ़ाइलों के लिए जाँच करके कस्टम कार्यान्वयन की तलाश करता है। डिफ़ॉल्ट कार्यान्वयन JDK (com.sun.org.*) के साथ शामिल हैं।

Xmlparserv2.jar के अंदर एक मेटा-आईएनएफ/सेवा निर्देशिका मौजूद है, जिसे javax.xml.parsers.FactoryFinder वर्ग उठाता है। फाइलें इस प्रकार हैं:

META-INF/services/javax.xml.parsers.DocumentBuilderFactory (which defines oracle.xml.jaxp.JXDocumentBuilderFactory as the default)
META-INF/services/javax.xml.parsers.SAXParserFactory (which defines oracle.xml.jaxp.JXSAXParserFactory as the default)
META-INF/services/javax.xml.transform.TransformerFactory (which defines oracle.xml.jaxp.JXSAXTransformerFactory as the default)

समाधान?

सभी 3 को वापस स्विच करें, अन्यथा आपको अजीब त्रुटियां दिखाई देंगी।

  • javax.xml.parsers.* दृश्यमान त्रुटियों को ठीक करें
  • javax.xml.transform.*अधिक सूक्ष्म XML पार्सिंग त्रुटियों को ठीक करता है
    • मेरे मामले में, अपाचे कॉमन्स कॉन्फ़िगरेशन के साथ पढ़ना/लिखना

एप्लिकेशन सर्वर स्टार्टअप त्रुटियों को हल करने के लिए त्वरित समाधान:JVM तर्क

Xmlparserv2.jar द्वारा किए गए परिवर्तनों को ओवरराइड करने के लिए, अपने एप्लिकेशन सर्वर स्टार्टअप तर्कों में निम्नलिखित JVM गुण जोड़ें। Java.xml.parsers.FactoryFinder तर्क पहले पर्यावरण चर की जाँच करेगा।

-Djavax.xml.parsers.SAXParserFactory=com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl -Djavax.xml.parsers.DocumentBuilderFactory=com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl -Djavax.xml.transform.TransformerFactory=com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl

हालांकि, अगर आप @RunWith(SpringJUnit4ClassRunner.class) या इसी तरह के प्रयोग का उपयोग करके टेस्ट केस चलाते हैं, तो भी आपको त्रुटि का अनुभव होगा।

एप्लिकेशन सर्वर स्टार्टअप त्रुटियों और परीक्षण केस त्रुटियों के लिए बेहतर समाधान? 2 विकल्प

विकल्प 1:ऐप सर्वर के लिए JVM तर्क और अपने परीक्षण मामलों के लिए @BeforeClass स्टेटमेंट का उपयोग करें

System.setProperty("javax.xml.parsers.DocumentBuilderFactory","com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl");
System.setProperty("javax.xml.parsers.SAXParserFactory","com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl");
System.setProperty("javax.xml.transform.TransformerFactory","com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl");

यदि आपके पास बहुत सारे परीक्षण मामले हैं, तो यह दर्दनाक हो जाता है। भले ही आप इसे सुपर में डाल दें।

विकल्प 2:अपने प्रोजेक्ट के लिए कंपाइल/रनटाइम क्लासपाथ में अपनी स्वयं की सेवा प्रदाता परिभाषा फ़ाइलें बनाएं, जो xmlparserv2.jar में शामिल फ़ाइलों को ओवरराइड कर देंगी

मावेन स्प्रिंग प्रोजेक्ट में, %PROJECT_HOME%/src/main/resources निर्देशिका में निम्न फ़ाइलें बनाकर xmlparserv2.jar सेटिंग्स को ओवरराइड करें:

%PROJECT_HOME%/src/main/resources/META-INF/services/javax.xml.parsers.DocumentBuilderFactory (which defines com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl as the default)
%PROJECT_HOME%/src/main/resources/META-INF/services/javax.xml.parsers.SAXParserFactory (which defines com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl as the default)
%PROJECT_HOME%/src/main/resources/META-INF/services/javax.xml.transform.TransformerFactory (which defines com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl as the default)

इन फ़ाइलों को दोनों एप्लिकेशन सर्वर (कोई JVM तर्क आवश्यक नहीं) द्वारा संदर्भित किया जाता है, और किसी भी कोड परिवर्तन की आवश्यकता के बिना किसी भी इकाई परीक्षण मुद्दों को हल करता है।

हो गया।



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Oracle में POWER () फंक्शन

  2. मैं LIKE ऑपरेटर में कई शर्तें कैसे पेश कर सकता हूं?

  3. crfclust.bdb . से उच्च स्थान का उपयोग

  4. क्या मुझे रिलेशनल डेटाबेस में एक पंक्ति को हटाना या अक्षम करना चाहिए?

  5. ऑरैकल डेटाबेस में बने रहते हुए समवर्ती अनुरोध को संभालना?