Получение оракула XMLType, хранящегося в виде двоичного XML, из набора результатов в Java

Я изложил решение для записи / чтения в столбец Oracle XMLType для Oracle 11g (в частности, 11.2.0.1), если столбец XMLType хранится как CLOB, что является значением по умолчанию для 11.2.0.1.

ССЫЛКА ОТВЕТА: Использование oracle XMLType в сценарии спящего режима Java Spring

В SQLDeveloper, если вы просматриваете вкладку SQL в определении таблицы (таблица DDL), она определяет хранение столбцов XML в 11.2.0.1 следующим образом:

 XMLTYPE COLUMN "ATTRIBUTE_XML2" STORE AS BASICFILE CLOB 

Проблема: в Oracle 11.2.0.2 типом хранения по умолчанию для XMLType является Binary XML, который является предпочтительным по соображениям производительности. Это выглядит так:

XMLTYPE COLUMN "ATTRIBUTE_XML2" STORE AS SECUREFILE BINARY XML

ОДНАКО, когда-то сохраненный таким образом, мое решение, на которое ссылаются, больше не работает для ЧТЕНИЯ столбца XMLType как XML из базы данных. Он возвращает некоторый мусор из xmlType.getStringVal(), который, как я полагаю, является двоичным закодированным XML оракулом.

Основная проблема Я не могу преобразовать обратно из формата оракула binxml в действительный документ XML.

Я пробовал Oracle BinXMLProcessor, BinXMLStream, BinXMLDecoder и InfosetReader в различных конфигурациях, как указано в Oracle, но они, похоже, просто читают, а не декодируют его, поэтому он выдает ошибки.

Базовый пример в nullSafeGet (см. Связанный ответ для контекста).

xmlType = (XMLType) rs.getObject(names[0]);
BinXMLProcessor xp = BinXMLProcessorFactory.createProcessor();
BinXMLStream bstr = xp.createBinXMLStream(xmlType.getInputStream());
BinXMLDecoder xdecode = bstr.getDecoder();
InfosetReader reader = xdecode.getReader();

while (reader.hasNext() && i < 25) {
    i++;
    reader.next();
    logger.debug("1 v:" + reader.getValue() + ", s:" + reader.getStandalone() + ", type: " + reader.getEventType() + ", " + reader.getDataLength());
}

Я попробовал похожие подходы, заменив xmlType.getInputStream() на xmlType.getBlobVal(178), xmlType.getBytesValue(), но все они выдают исключение или возвращают данные мусора.

Да.

1 ответ

Решение

Нашел подвох, и это не имеет отношения к коду.

Правильный nullSafeGet в Hibernate UserType, как отмечено в указанном ответе:

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);
    }
}

ПРОБЛЕМА: при использовании столбца SECUREFILE BINARY XML (не CLOB) вы должны использовать самый последний (11.2.0.2+) дистрибутив xdb*.jar, который в данном случае является xdb6.jar (~257kb). Более ранняя версия xdb*.jar (~136 Кбайт для 10.x) будет по-прежнему функционировать без каких-либо исключений даже при неправильном декодировании BINARY XML.

TL; DR: Загрузите xdb6.jar (~ 257 КБ) со страницы драйверов JDBC для Oracle 11gR2 (11.2.0.3). Старые xdb баночки молча терпят неудачу и огорчают вас.

Другие вопросы по тегам