Работа с XML на различных уровнях приложения: Часть 2. Создание эффективных приложений Java EE, использующих сервер базы данных XML

Оптимизация решения, целиком основанного на XML, с помощью JDBC 4.0, SQLXML, пакета дополнений XML WebSphere и DB2 pureXML

В первой части этого цикла статей представлен подход декларативного программирования для работы с временными и сохраненными XML-данными на уровнях сервера приложений и сервера баз данных. В этой статье глубже рассматривается работа с временными и сохраненными XML-данными в серверном Java™-приложении. На практических примерах и образцах кода показано, как возможности XML-индексирования и фильтрации запросов в системе управления базами данных обеспечивают важные преимущества для производительности приложений Java EE, работающих с большими объемами XML-данных. Мы покажем также, как соединить временные XML-данные с сохраненными.

Эндрю Спайкер, STSM, архитектор групп WebSphere XML, SOA и оптимизации, IBM

Photo of Andrew SpykerЯвляясь старшим техническим специалистом (Senior Technical Staff Member - STSM) групп разработчиков WebSphere Application Server, Эндрю Спайкер (Andrew Spyker) занимается следующими основными вопросами. Во-первых, он консультирует специалистов по оптимизации, используя свой пятилетний опыт руководства группой оптимизации WebSphere Application Server. Во-вторых, являясь архитектором среды выполнения SOA, он отвечает за согласованность сред SOA в WebSphere на всех уровнях, уделяя основное внимание стратегиям эталонных испытаний, производительности и согласованности XML. В-третьих, большую часть своего времени он уделяет созданию и развитию стратегии работы с XML в линейке продуктов WebSphere. Последнее время он выполнял функции главного архитектора пакета дополнений XML для WebSphere Application Server.



Синтия M. Саракко (Cynthia M. Saracco), старший инженер-программист, IBM

C. M. Саракко (Cynthia M. Saracco) работает в исследовательской лаборатории компании IBM в Силиконовой долине, в объединении DB2 XML. Сфера ее служебных интересов – управление базами данных, XML, разработка веб-приложений и смежные темы.


developerWorks Professional author
        level

Роберт Ван-дер-Линден, старший технический специалист, IBM

Фото Роберта Ван-дер-ЛинденаРоберт Ван-дер-Линден (Robbert (Bert) Van der Linden) работает старшим техническим специалистом (STSM) в IBM Silicon Valley Laboratory. Присоединился к команде разработчиков IBM в 2001 г., начав работать над проектом pureXML в DB2, который завершился выпуском DB2 9 в 2006 году. Параллельно работал со многими клиентами и партнерами, помогая использовать XML в базах данных, и продолжает интенсивно сотрудничать с заказчиками. Роберт пришел в IBM из молодой компании Propel, где он руководил проектированием и разработкой распределенного и отказоустойчивого программного обеспечения для хостинга масштабируемого приложения электронной коммерции. До этого много лет работал в компании Tandem Computers над продуктом NonStop SQL – СУБД, которая используется во многих важных финансовых приложениях.



Гогэнь Чзан, ведущий инженер, IBM

Фото Гогэнь ЧзанаГогэнь Чзан (Guogen Zhang) ― ведущий инженер по разработке DB2 для Z/OS в IBM Silicon Valley Laboratory. Главный архитектор и ведущий разработчик, ответственный за выпуск pureXML в составе DB2 для Z/OS. Руководит созданием передовой технологии SQL и выпустил важные функциональные модули, в том числе pureXML, Materialized Query Tables (MQTs), средства публикации XML, реализации метода star join, union in view и другие возможности DB2 для z/OS. Часто выступает на конференциях, таких как НОР и IDUG, и принимает активное участие в создании pureXML-решений для заказчиков.



18.07.2012

11 октября 2010 г.- В разделе Загрузки добавлен файл fpmldb2was.zip.

Обзор

Широкое применение XML побуждает программистов искать эффективные способы работы как с временными XML-сообщениями, так и с сохраненными XML-данными. Web-сервисы и другие компоненты ПО зачастую приводят к созданию временных XML-сообщений, содержащих важные бизнес-данные. Приложениям все чаще приходится обрабатывать такие сообщения, а также деловые документы, хранящиеся в системе управления базами данных XML.

Часто используемые сокращения

  • API: Application programming interface – интерфейс прикладных программ
  • BLOB: Binary large object – большой двоичный объект
  • CLOB: Character large object – большой символьный объект
  • DBMS: Database Management System – система управления базами данных
  • DOM: Document Object Model
  • JDBC: Java Database Connectivity
  • OEM: Original equipment manufacturer – изготовитель комплектного оборудования
  • SAX: Simple API for XML – простой API для XML
  • SOA: Service-oriented architecture – сервис-ориентированная архитектура
  • SQL: Structured Query Language – язык структурированных запросов
  • URI: Uniform Resource Identifier – универсальный идентификатор ресурса
  • URL: Uniform Resource Locator – универсальный указатель ресурса
  • W3C: World Wide Web Consortium
  • XHTML: Extensible HyperText Markup Language – расширяемый гипертекстовый язык разметки
  • XML: Extensible Markup Language – расширяемый язык разметки
  • XSLT: Extensible Stylesheet Language Transformations

Безусловно, на Java-объекты можно отобразить как временные, так и сохраненные XML-данные, но для многократно вложенных, сложных структур XML это может оказаться затруднительным. Кроме того, если схемы XML-данных с течением времени могут меняться, код приложения может стать еще сложнее. В первой статье этого цикла был представлен декларативный подход к программированию для работы с временными и сохраненными XML-данными на уровнях сервера приложений и сервера баз данных, часто позволяющий упростить программирование по сравнению с императивными подходами.

В этой статье глубже рассматривается работа с временными и сохраненными XML-документами в Java-приложении на сервере. Рассмотрев общие задачи разработки приложений и образцы кода, вы:

  1. научитесь использовать родную стандартную технологию сервера базы данных из приложений Java EE, в которые необходимо эффективно интегрировать динамические и статические XML-данные;
  2. узнаете, как использовать возможности индексации XML и фильтрации запросов в системе управления базами данных для обеспечения высокой производительности;
  3. а также поймете, как объединить временные XML-данные с сохраненными и как обновлять только нужные части статических XML-документов.

Предварительные требования и продукты

Эта статья рекомендуется тем, кто знаком с XML, XPath и XQuery. Информацию об этих технологиях можно найти по ссылкам в разделе Ресурсы. Кроме того, следует прочесть первую статью этого цикла, поскольку примеры в этой статье основаны на WebSphere Application Server V7.0 Feature Pack для XML 1.0. Также будет полезно знание технологии управления базами данных XML. В качестве сервера базы данных XML в примерах для этой статьи мы используем DB2®.

Среда примера приложения и образец базы данных

Чтобы рассмотреть, как разработчики серверных Java-программ могут эффективно работать с временными и сохраненными XML-данными, мы установили на одну Windows®-систему следующее программное обеспечение:

  • Rational Application Developer для WebSphere Software V7.5.5 с тестовой средой WebSphere Application Server 7.0;
  • WebSphere Application Server Feature Pack для XML 1.0 с Fix Pack 1.0.0.7. (Это можно использовать с автономной версией WebSphere Application Server, а также с тестовой средой WebSphere, встроенной в Rational Application Developer.);
  • DB2 9.7 Enterprise Server Edition.

В состав сборки нашего проекта разработки Rational Application Developer войдут файлы .jar драйвера JDBC 4.0 DB2.Это файлы db2jcc4.jar и db2_license_cu.jar. Чтобы использовать в проекте XML Feature Pack, нужно разрешить XML Transformation и Query Project Facet, щелкнув правой кнопкой на проекте, выбрав Project Facets и разрешив фасет. Иначе, можно добавить в свою сборку архив jar тонкого клиента XML Feature Pack (com.ibm.xml.thinclient_1.0.0.jar). Подробнее о драйвере JDBC 4.0 в DB2 или о XML Feature Pack можно прочесть по ссылкам в разделе Ресурсы.

База данных для нашего примера содержит записи о торгах внебиржевыми (over-the-counter – ОТС) деривативами, основанные на выборочных данных XML Международной ассоциации свопов и деривативов (ISDA). Формат этих данных соответствует спецификации Financial Products Markup Language (FpML), которая пользуется популярностью у многих фирм, торгующих деривативами.

Для DB2 есть целый ряд бесплатных отраслевых загружаемых модулей программного обеспечения, которые помогают фирмам быстро создать и заполнить тестовую базу данных в соответствии со стандартным отраслевым XML-форматом. Такой пакет имеется и для FpML. Мы настроили его так, чтобы проиллюстрировать определенные моменты этой статьи; эту версию можно загрузить по ссылке в разделе Загрузки. Чтобы установить образец базы данных на Windows-систему, откройте окно командной строки DB2 и наберите start.bat. Это приведет к созданию необходимых объектов базы данных и загрузке образца данных FpML.

В наших примерах используется таблица FPMLADMIN.FPML43, которая содержит два столбца реляционных данных (ID и COMMENT), а также один столбец XML (DOCUMENT). В столбце XML хранятся полные FpML-протоколы торгов деривативами различных типов. Фирмы часто хранят в одной таблице как реляционные, так и XML-данные, и наши примеры ссылаются на оба типа столбцов. Структура этой таблицы иллюстрируется на рисунке 1.

Рисунок 1. Таблица FPMLADMIN.FPML43 с двумя реляционными столбцами (ID и COMMENT) и одним столбцом XML (DOCUMENT)
Таблица FPMLADMIN.FPML43 с двумя реляционными столбцами (ID и COMMENT) и одним стобцом XML (DOCUMENT)

Записи FpML содержат многократно вложенные структуры с элементами и атрибутами, зависящими от типа представленных торгов. Рисунок 2 иллюстрирует небольшую часть образца FpML-протокола торгов свопами на дефолт по кредиту.

Рисунок 2. Часть FpML-протокола торгов свопами на дефолт по кредиту
Часть FpML-протокола торгов свопами на дефолт по кредиту

Наш образец таблицы содержит FpML-документы размером от 2 КБ до 125 КБ. Более того, в одном и том же столбце XML таблицы хранятся документы по торгам, основанные на трех разных версиях схемы FpML. (В частности, документы на основе FpML 4.2, 4.3 и 4.7.) XML-схемы, как правило, развиваются с течением времени в соответствии с меняющимися потребностям бизнеса, так что хранение документов, отвечающих различным схемам, в одном столбце XML ― обычное явление.


Запрос сохраненных XML-данных

Разработчикам Java EE-приложений часто приходится извлекать сохраненные XML-данные, которые хранятся на уровне базы данных, и манипулировать этими данными на уровне сервера приложений. Чтобы продемонстрировать это, мы воспользуемся примером с использованием API XML Feature Pack и встроенной в DB2 поддержки запросов для XML-данных. Оба предложения поддерживают отраслевые стандарты запросов XML-данных, в том числе выражения XQuery и XPath.

Поскольку DB2 распознает и поддерживает XML-данные в качестве типа данных первого класса, программисты могут работать непосредственно с XML-данными в их собственном формате, а не как с большими объектами (LOB). Использование XML на нескольких уровнях программного обеспечения упрощает программирование логики и снижает стоимость разработки. Более того, встроенная поддержка XML в DB2, в отличие от LOB, обеспечивает эффективный доступ к определенным частям (XML-узлам) документа.

Сценарий запроса

Рассмотрим ситуацию, в которой приложениию Java EE необходимо получить доступ к информации о свопах на дефолт по кредиту, соответствующую определенной сделке. Если данные торгов передаются в приложение в качестве временного XML-сообщения, приложение может просто использовать XML Feature Pack для выполнения XPath-выражения в отношении этого сообщения. Такое XPath-выражение приведено в листинге 1.

Листинг 1. Использование XML Feature Pack API для работы с временным XML
// Это XPath-выражение получает данные о свопах на дефолт по кредиту для данной сделки.   
// Для простоты мы опустили здесь объявление специального пространства имен. 

String myXpath = "*:FpML/*:trade/*:creditDefaultSwap;
. . .

Не все приложения опираются на временные XML-сообщения. Приложению, предназначенному для работы с корпоративным портфелем ценных бумаг с целью анализа инвестиционных стратегий, управления рисками или выполнения некоторых других бизнес-функций, возможно, потребуется получать нужные данные о торгах из сохраненного XML-хранилища.

Пример запроса, возвращающего фрагмент сохраненных XML-данных о торгах

В листинге 2 показано, как использовать выражения XPath для получения сведений о сделках со свопами на дефолт по кредиту с участием нужной компании из базы данных – в данном случае, DB2.

Листинг 2. SQL/XML-запрос с реляционными и XML-предикатами
SELECT XMLQUERY('declare default element namespace 
   "http://www.fpml.org/2009/FpML-4-7";
   $fpml/FpML/trade/creditDefaultSwap' passing document as "fpml")
FROM fpmladmin.fpml43 
WHERE comment LIKE вЂ˜cd%’ 
AND 
XMLEXISTS('declare default element namespace "http://www.fpml.org/2009/FpML-4-7";
   $fpml/FpML/trade/creditDefaultSwap/generalTerms/referenceInformation
   /referenceEntity[entityName="Agrium Inc."]' passing document as "fpml")

Этот запрос, который может быть выполнен в интерактивном режиме посредством интерфейса командной строки DB2 или графического инструмента запросов, представляет собой стандартный SQL-оператор, который вызывает две специфических XML-функции. Первая, XMLQUERY(), определяет данные, которые мы хотим получить (данные узла creditDefaultSwap). Вторая функция, XMLEXISTS(), ограничивает результаты документами FpML 4.7, которые указывают на определенную компанию (Agrium Inc).

Как и большинство SQL-операторов, этот пример следует стандартному синтаксису SQL SELECT column(s). . . FROM table(s) . . . WHERE condition(s). Давайте разберем этот запрос более подробно, а затем рассмотрим пример Java-кода, который показывает, как можно вызывать этот запрос в приложении, использующем XML Feature Pack.

В первой строке запроса выдается оператор SQL SELECT, который вызывает стандартную отраслевую SQL-функцию (XMLQUERY). Вызвав XMLQUERY(), мы сначала объявляем нужное целевое пространство имен (http://www.fpml.org/2009/FpML-4-7). Как уже говорилось, наша выборка таблицы DB2 содержит в одном столбце разные версии FpML-записей, но нас интересует только конкретная запись FpML 4.7.

Объявив пространство имен по умолчанию для функции XMLQuery, мы приводим выражение XPath, определяющее данные, которые нужно получить ($fpml/FpML/trade/creditDefaultSwap). Выражение passing, следующее за выражением XPath, говорит о том, что переменная $fpml соответствует столбцу DOCUMENT нашей таблицы. Таким образом, первые три строки листинга 2 указывают, что мы хотим извлечь только часть данных о торгах из протокола торгов FpML 4.7, хранящегося в столбце ДОКУМЕНТ. В частности, нам нужны только данные о свопах на дефолт по кредиту, которые в FpML представлены как XML-узел, содержащий несколько дочерних узлов (см. рисунок 2). Предложение SQL FROM определяет в качестве интересующей нас таблицы FPMLADMIN.FPML43.

Предложение SQL WHERE указывает, что мы хотим получить только результаты, относящиеся к торгам дефолтами по кредиту. В нашем примере таблицы значения в столбце COMMENT (реляционный столбец) могут использоваться для выделения типа торгов, записанного в столбце DOCUMENT(XML-столбец). Торгам дефолтами по кредиту соответствуют значения COMMENT, начинающиеся с cd.

Остальные строки вызывают стандартную функцию XMLEXISTS(), которая ограничивает результаты запроса свопами с участием конкретной компании Agrium Inc. Более внимательный взгляд на функцию XMLEXISTS показывает, что она объявляет соответствующее пространство имен и содержит выражение XPath, которое сервер баз данных будет выполнять по отношению к данным, содержащимся в столбце таблицы DOCUMENT.

Для достижения лучшего быстродействия среды исполнения Java EE-программисты делают запросы как можно более селективными. Наш пример запроса получает только нужную нам часть XML-данных (в частности, функция XMLQUERY получает только конкретный XML-узел протокола торгов). Кроме того, в нашем примере запроса нужные строки квалифицируются путем указания реляционных и XML-предикатов в предложении WHERE. Составляя запрос таким образом, мы минимизируем объем данных, передаваемых между уровнями базы данных и сервера приложений. (В нашем примере извлекается подмножество одной XML-записи торгов, хранящейся в DB2, тогда как более общий запрос, охватывающий все сделки со свопами на дефолт по кредиту, возвратил бы сорок полных записей.) Наконец, определение соответствующих XML-индексов в DB2 позволяет ускорить обработку запросов в среде исполнения, о чем мы скажем ниже.

Пример кода Java EE для нашего сценария запроса

Этот запрос к базе данных нетрудно включить в приложение Java EE. Рассмотрим пошаговый пример, который извлекает нужные XML-данные из базы данных и манипулирует этими данными на сервере приложений.

В листинге 3 приведен отрывок сервлета, определяющий запрос к базе данных, который будет выполняться соответствующим конструктором набора XML Feature Pack.

Листинг 3. Приложение Java EE, которое применяет программу XQuery к данным DB2 pureXML®, считываемым в оперативную память
// Выдержка из нашего примера сервлета.  
//  
// Сначала сервлет создает запрос к базе данных.  
// Здесь на наш запрос, который извлекает из подходящих сделок узел creditDefaultSwap,  
// будет отображаться строка с именем "getCreditDefaultSwapsByEntityName". 

dbStatements = new HashMap<String, String>();
dbStatements.put("getCreditDefaultSwapsByEntityName",
 "select " +
   "xmlquery("'declare default element namespace " + 
     "\"http://www.fpml.org/2009/FpML-4-7\"; " + 
     "$DOCUMENT/FpML/trade/creditDefaultSwap' ) " +
  "from fpmladmin.fpml43 " + 
  "where comment like ? and " +
  "xmlexists("'declare default element namespace " + 
    "\"http://www.fpml.org/2009/FpML-4-7\"; " +
    "$fpml/FpML/trade/creditDefaultSwap/generalTerms/" + 
    "referenceInformation/referenceEntity[entityName=$name]' " +
    "passing document as \"fpml\", " +
    "cast (? as varchar(100)) as \"name\")"
);
...

// Далее, другой метод этого сервлета создает исполняемый файл XQuery.      
// Затем этот метод использует наш конструктор JDBC для его исполнения, 
// выдавая соответствующее значение переменной entityName.  

Source source = 
   new Source(FpMLServlet.class.getResource("/getCreditDefaultSwaps.xq").toString());
XQueryExecutable getCreditDefaultSwapsXQ = factory.prepareXQuery(source, staticContext);
...
JDBCCollectionResolver inputResolver =
  new JDBCCollectionResolver(getConnection(), dbStatements);
dynamicContext.setCollectionResolver(inputResolver);
dynamicContext.bind(new QName("http://com.ibm.xml.samples",entityName"), name);
XSequenceCursor output = getCreditDefaultSwapsXQ.execute(dynamicContext);

Запрос из первой части листинга 3 почти идентичен интерактивной версии из листинга 2. Важно отметить следующие различия:

  • маркеры параметров, обозначаемые вопросительным знаком (?), заменяют жестко запрограммированные значения предиката, что обеспечивает повышенную гибкость;
  • двойные кавычки надлежащим образом исключены.

Если именованный запрос определен правильно, приложение может выполнить его и применить к возвращаемым результатам бизнес-логику. Для простоты, бизнес-логика, показанная в этом примере, просто получает ставку купона и другую информацию о корпоративных облигациях, относящуюся к нужным сделкам. Реальное приложение будет содержать более сложную бизнес-логику.

Вторая часть кода, приведенного в листинге 3, содержит логику, которая получает соответствующие XML-данные из базы данных сервера и манипулирует ими в сервере приложений. Этот код шаблона следует тому же подходу, что и в примере из первой статьи этого цикла (см. раздел Ресурсы). Во-первых, приложение создает исполняемый объект XQuery, который XML Feature Pack выполнит по отношению к части XML-записи о сделке, возвращенной DB2. Затем приложение указывает соответствующий конструктор коллекции. Конструктор подключается к базе данных DB2 и выполняет запрос, передавая соответствующее значение данных маркеру параметра запроса (имя указанной компании, участвующей в сделке).

Наша реализация конструктора совпадает с той, что описана в листинге 8 первой статьи, поэтому мы не будем рассматривать ее здесь подробно. Этот конструктор работает с коллекциями, которые начинаются со схемы URI jdbc://. Он использует именованные запросы для определения оставшейся части URI и выполняет соответствующую логику. Этот конструктор, как и весь остальной код примера из данной статьи, можно загрузить. См. ссылки в разделе Загрузки.

Отметим, что используемый здесь конструктор основан на примере, который прилагается к XML Feature Pack, и представляет собой лишь один из способов доступа к базе данных XML (например, DB2 pureXML). Чтобы использовать этот код в реальном приложении, нужно по мере необходимости изменить или расширить этот пример. Кроме того, в первой статье цикла кратко обсуждались другие возможные подходы к проектированию конструктора, например, см. листинг 14 той статьи (см. раздел Ресурсы).

Когда нужные данные по свопу на дефолт по кредиту извлечены из базы данных, приложение может манипулировать этими данными в соответствии с требованиями. В листинге 4 показана функция XQuery, которая выполняется на сервере приложений, извлекая идентификатор инструмента, купонную ставку и срок погашения корпоративной облигации, указанный в каждой сделке, извлеченной из базы данных.

Листинг 4. Выдержка из getCreditDefaultSwaps.xq, программа XML Feature Pack XQuery для получения информации об облигациях, участвующих в сделке
declare variable $my:entityName as xs:string external; 

declare variable $databaseURI := 
	concat('jdbc://getCreditDefaultSwapsByEntityName?cd%&', $my:entityName); 
declare variable $creditDefaultSwaps := collection($databaseURI); 

for $bond in $creditDefaultSwaps//fpml:bond
	return  
<tr>   
	<td>{ $bond/fpml:instrumentId }</td>   
	<td>{ $bond/fpml:couponRate }</td>   
	<td>{ $bond/fpml:maturity }</td>  
</tr>

Создание индексов для улучшения производительности среды исполнения

Теперь, когда вам понятна логика получения нужных XML-данных из базы данных и манипулирования ими в промежуточном слое, обратимся к другой теме: производительности. Чтобы обеспечить эффективное выполнение нашего запроса на уровне базы данных, мы создали два индекса по таблице FPMADMIN.FPML43:

  • FPMLADMIN.COMMENTX, который индексирует реляционный столбец COMMENT;
  • FPMLADMIN.ENTITYNAME, который индексирует конкретный узел в столбце XML DOCUMENT.

Как вы вскоре увидите, DB2 для создания эффективного пути доступа к нашему запросу может использовать оба этих индекса. В листинге 5 показано, как создать эти индексы. Первый оператор определяет реляционный индекс, а второй определяет индекс XML.

Листинг 5. Создание реляционного и XML-индексов
create index fpmladmin.commentx on fpmladmin.fpml43(comment)

create index fpmladmin.entityname on fpmadmin.fpml43(document) 
generate key using xmlpattern  
  'declare default element namespace "http://www.fpml.org/2009/FpML-4-7"; 
  /FpML/trade/creditDefaultSwap/generalTerms/referenceInformation
       /referenceEntity/entityName' 
as sql varchar(1000)

Мы создали эти индексы, поскольку таблица FPMLADMIN.FPML43 в примере базы данных имеет объем 4 МБ и содержит около 900 строк. К тем свопам на дефолт по кредиту, в которых в качестве юридического лица указана наша целевая компания (Agrium Inc.), относится лишь небольшое количество данных. DB2 может использовать как реляционный, так и XML-индексы для быстрого выделения интересующих нас данных, избегая дорогостоящего просмотра всех строк таблицы.

Рисунок 3 иллюстрирует план доступа, который DB2 выбрала для нашего запроса после того, как мы собрали соответствующие статистические данные с помощью встроенного в DB2 инструмента RUNSTATS. Читая снизу вверх, вы заметите, что для быстрого извлечения данных, запрашиваемых нашим примером приложения, DB2 использовала оба индекса.

Рисунок 3. DB2 использует реляционный и XML-индексы для эффективного доступа к данным
DB2 использует реляционный и XML-индексы для эффективного доступа к данным

За более подробной информацией о просмотре и интерпретации планов доступа к данным DB2 обращайтесь к разделу Ресурсы.


Запрос временных и сохраненных XML-данных

XML Feature Pack позволяет также писать выражения XQuery, которые соединяют временные XML-данные – порожденные Web-сервисами или Java-приложениями – с сохраненными XML-данными. Понятно, что существуют разные способы достижения этой цели. Мы рассмотрим один из этих подходов.

Сценарий соединения

Рассмотрим приложение, анализирующее инвестиции в деривативы. Одним из аспектов этого приложения может быть получение текущих данных о фирмах, участвующих в торгах свопами на дефолт по кредиту. Простой пример таких данных может содержать информацию о текущих ценах на акции. В предположении, что записи о торгах деривативами хранятся в DB2, а информацию об акциях можно получить через Web-сервис, нам нужно сделать так, чтобы приложение соединило временные XML-данные с сохраненными.

Пример кода Java EE для нашего сценария соединения

Листинг 6 иллюстрирует один из способов использования XML Feature Pack для выполнения требуемой работы. Для получения свопа на дефолт по кредиту из DB2 мы применяем тот же запрос, что и в листинге 3, поэтому не будем здесь повторяться. Чтобы выполнить запрос, мы используем подходящий конструктор, почти так же, как в предыдущем сценарии.

Новое в листинге 6 ― это определение другого исполняемого файла XQuery – в частности, функции XQuery, которая обрабатывает соединение в XML Feature Pack. Кроме того, листинг 6 создает объект StreamSource для представления временных XML-данных, которые будут соединены с соответствующими данными о торгах, хранящимися в DB2. Для простоты наш StreamSource заполнен данными из файла с именем assets.xml, который мы используем в качестве источника временных данных о рынке, полезных для анализа портфеля. (В реальном приложении эти данные XML, скорее всего, будут поступать от Web-сервиса или из очереди сообщений.)

Листинг 6. Приложение Java EE, соединяющее временные и сохраненные XML-данные
// Создание исполняемого кода XQuery .   
Source source = 
    new Source(FpMLServlet.class.getResource("/joinCreditDefaultSwap.xq").toString());
XQueryExecutable joinCreditDefaultSwapsXQ = factory.prepareXQuery(source, staticContext);
...

// Объявление конструктора и выполнение соединения.  
// Конструктор выдает запрос к DB2, а программное  
// обеспечение  WebSphere соединяет результат 
// с XML-данными из объекта StreamSource.  
JDBCCollectionResolver inputResolver = 
    new JDBCCollectionResolver(getConnection(), dbStatements);
dynamicContext.setCollectionResolver(inputResolver);
StreamSource source = 
    new StreamSource(FpMLServlet.class.getResourceAsStream("/assets.xml"));
dynamicContext.bind(new QName("http://com.ibm.xml.samples", "entityName"), name);
XSequenceCursor output = joinCreditDefaultSwapsXQ.execute(source, dynamicContext);

В листинге 7 показано содержимое файла assets.xml.

Листинг 7. Содержание assets.xml, которое в нашем примере представляет собой временные XML-данные
<?xml version="1.0" encoding="UTF-8"?>
<assets>
     <equity>
          <symbol>AGU</symbol>
          <name>Agrium Inc.</name>
          <currency>USD</currency>
          <high>64.06</high>
          <low>62.79</low>
     </equity>
     <equity>
          <symbol>STM-FP</symbol>
          <name>STMicroelectronics N.V.</name>
          <currency>EUR</currency>
          <high>6.92</high>
          <low>7.2</low>
     </equity>
</assets>

Листинг 8 содержит функцию XQuery, которая соединяет временные и сохраненные XML-данные.

Листинг 8. Выдержка из программы XML Feature Pack XQuery joinCreditDefaultSwaps.xq, которая выполняет соединение
declare variable $my:entityName as xs:string external;

declare variable $databaseURI := 
    concat('jdbc://getCreditDefaultSwapsByEntityName?cd%&', $my:entityName); 
declare variable $creditDefaultSwaps := collection($databaseURI);

declare function local:equityRows($root) {
     for $equity in $root//equity
     let $referenceEntity := $creditDefaultSwaps//fpml:referenceEntity
     where $equity/name = $referenceEntity/fpml:entityName
     return
          <tr xmlns="http://www.w3.org/1999/xhtml">
               <td>{ $equity/*:symbol/text() }</td>
               <td>{ $equity/*:name/text() }</td>
               <td>{ $equity/*:high/text() }</td>
               <td>{ $equity/*:currency/text() }</td>
          </tr>
};

<table border="1">
<tr>
     <th>Ticker Symbol</th>
     <th>Company Name</th>
     <th>High</th>
     <th>Currency</th>
</tr>
{ local:equityRows(/) }
</table>

Предложение FOR этой функции циклически опрашивает узлы организаций, содержащиеся во временных XML-данных. Предложение LET извлекает нужную информацию о компании из коллекции данных о свопах на дефолт по кредиту, которые DB2 возвращает после выполнения именованного запроса, определенного в Листинге 6. Предложение WHERE соединяет временные и сохраненные XML-данные на основе имен активов. Функция возвращает сведения в формате XHTML о символе акции, названии компании, максимальной цене продажи и валюте для всех фирм, упоминаемых в свопах на дефолт по кредиту, извлеченных из DB2.

При соединении временных и сохраненных XML-данных важно учитывать, где должно происходить это соединение. Если один уровень программного обеспечения содержит большое количество данных, которые нужно соединить с малым объемом данных, находящихся на другом уровне, соединение обычно эффективнее выполненять на уровне с большим количеством данных.


Обновление сохраненных XML-данных

Другое распространенное требование, предъявляемое к Java EE-приложениям на основе XML, – это обновление сохраненных XML-данных. В первой статье этого цикла содержится образец кода, который показывает, как заменить сохраненный документ другим XML-документом из оперативной памяти. В некоторых ситуациях, безусловно, полезен вариант полного обновления документа. Однако во многих приложениях нужно обновить только часть XML-документа. Рассмотрим, как это сделать.

DB2 поддерживает XQuery Update Facility, стандартизированное расширение XQuery, которое позволяет программистам обновлять определенные XML-узлы разными способами. Например, можно добавлять новые узлы, удалять их, обновлять значения элементов и атрибутов, а также вносить другие изменения. Обновление части документа часто помогает улучшить производительность среды исполнения. Программисты просто указывают изменения, которые они хотели бы внести в соответствующие части XML-документа. DB2 выполняет эти обновления непосредственно на сервере, сводя к минимуму логику программирования приложения и передачу данных, которая в противном случае имела бы место. Напротив, СУБД, которые для управления XML опираются на объекты CLOB или BLOB, требуют, чтобы для извлечения XML-документов из базы данных приложение анализировало эти документы, обновляло их по мере необходимости, а затем записывало эти документы обратно в базу данных. Если требуется изменить только малую часть крупного XML-документа, потери с точки зрения производительности при таком подходе могут быть значительными.

Сценарий обновления

Рассмотрим сценарий, в котором приложению необходимо изменить значение XML-узла. Например, два участника торгов свопами на дефолт по кредиту могут пересмотреть условия, связаннее со сроком погашения, который представлен в виде узла в FpML-протоколе торгов. Чтобы отразить эти новые условия, которые могут быть переданы в приложение Java EE в форме временного XML-сообщения, необходимо отредактировать FpML-протокол торгов, хранящийся в базе данных.

Для соблюдения нормативных требований фирмы, участвующие в торгах деривативами, часто представляют в своих базах данных измененные протоколы торгов как новые записи. Мы же в учебных целях покажем, как непосредственно изменить исходную FpML-запись.

Пример частичного обновления сохраненных XML-данных

В листинге 9 присутствует интерактивный SQL-оператор, который обновляет XML-данные в столбце DOCUMENT таблицы FPMLADMIN.FPML43.

Листинг 9. Обновление XML-узла документа хранящегося в DB2
update FPMLADMIN.FPML43 
set document = 
  xmlquery ('declare default element namespace "http://www.fpml.org/2009/FpML-4-7";
    transform copy $new := $x 
    modify do replace 
      $new/FpML/trade/creditDefaultSwap/generalTerms/scheduledTerminationDate 
    with 
      <scheduledTerminationDate xmlns="http://www.fpml.org/2009/FpML-4-7">
         <adjustableDate>
            <unadjustedDate>2011-05-05</unadjustedDate>
            <dateAdjustments>
               <businessDayConvention>FOLLOWING</businessDayConvention>
            </dateAdjustments>
         </adjustableDate>
         <comment>This is new.</comment>
      </scheduledTerminationDate>
    return $new' passing document as "x")
where comment like 'cd-ex10-long-us-corp-fixreg-47%'and
  xmlexists('declare default element namespace "http://www.fpml.org/2009/FpML-4-7";
    $fpml/FpML/trade/creditDefaultSwap/generalTerms
    /referenceInformation/referenceEntity[entityName="Agrium Inc."]' 
    passing document as "fpml")

Предложение WHERE ограничивает обновление конкретной сделкой со свопами на дефолт по кредиту с участием Agrium Inc. Так как логика этого пункта очень похожа на логику, представленную в предыдущих сценариях, мы не будем рассматривать ее вновь.

Самая интересная часть этого запроса содержится в выражении, включенном в вызов функции XMLQuery(). После объявления соответствующего пространства имен по умолчанию это выражение копирует исходное значение из XML-документа (см. рисунок 2) в переменную $new. Предложение MODIFY заменяет узел срока погашения новым. Этот новый узел эффективно изменяет первоначального узел в четыре приема.

  1. Нескорректированное значение срока погашения (дочерний узел) заменяется новым (5 мая 2011 г.).
  2. Значение соглашения о рабочих днях (дочерний узел) изменяется на FOLLOWING (следующий).
  3. Дочерний узел бизнес-центров удаляется. (В результате удаляются также и дочерние узлы бизнес-центров.)
  4. Добавляется новый дочерний узел комментариев.

Наконец, предложение RETURN возвращает новый узел, соответствующий запланированному сроку погашения, так что DB2 заменит данные в столбце DOCUMENT измененными данными.

Пример кода Java EE для сценария обновления

Посмотрим, как реализовать эту операцию обновления в приложении Java EE. Как вы догадываетесь, при включении этого запроса в приложение нужно использовать маркеры параметров и управляющие символы. Первая часть листинга 10 показывает, как мы в нашем приложении Java EE превратили интерактивный оператор UPDATE (из листинга 9) в именованный запрос. Как и в предыдущих сценариях, этот пример для выполнения операции с базой данных полагается на конструктор.

Листинг 10. Замена XML-элемента с использованием DB2 pureXML
// Определение запроса к базе данных.  
// В данном случае именованный запрос выполняет 
// частичное обновление FpML-протокола торгов.  
dbStatements = new HashMap<String, String>();
dbStatements.put(
  "updateScheduledTerminationDateByEnityName",
  "update fpmladmin.fpml43 set document = " + 
  "xmlquery('" +
    "declare default element namespace " + 
       "\"http://www.fpml.org/2009/FpML-4-7\"; " +
     "transform copy $new := $x " +
     "modify do replace " +
       "$new/FpML/trade/creditDefaultSwap/generalTerms/scheduledTerminationDate with $d "+
     "return $new' " +
     "passing cast (? as xml) " +
     "as \"d\", " +
     "document as \"x\"" +
  ") " +			
  "where comment like ? and " +
    "xmlexists(" +
        "'declare default element namespace " + 
            "\"http://www.fpml.org/2009/FpML-4-7\"; " +
        "$fpml/FpML/trade/creditDefaultSwap/generalTerms" +
            "/referenceInformation/referenceEntity[entityName=$name]'" +
        "passing document as \"fpml\", cast (? as varchar(100)) as \"name\"" +
     ")"
);
...

// Создание исполняемого XSLT-файла и его  запуск с помощью JDBC-конструктора 
Source source = 
  new Source(FpMLServlet.class.getResource("/updateCreditDefaultSwap.xsl").toString());
XSLTExecutable updateCreditDefaultSwapXSL = 
  factory.prepareXSLT(source, staticContext);
...
JDBCResultsResolver resultsResolver = 
  new JDBCResultsResolver(getConnection(), dbStatements);
dynamicContext.setResultResolver(resultsResolver);
dynamicContext.bind(new QName("http://com.ibm.xml.samples","entityName"),"Agrium Inc.");
dynamicContext.bind(new QName("http://com.ibm.xml.samples","tradeType"),"cd-ex10-long%");
dynamicContext.bind(new QName("http://com.ibm.xml.samples","updateOrRestore"),"update");
...

// "newDate" – это XML из не-DB2 источника XML-данных
XItemView newDate = getUpdatedTerminationDate();
dynamicContext.bind(new QName("http://com.ibm.xml.samples",
   "updatedScheduledTermination"), newDate);
...
StreamResult result = new StreamResult(servletResponse.getOutputStream());
updateCreditDefaultSwapXSL.execute((Source)null, dynamicContext, result);

В данном примере, вместо того чтобы использовать программу XQuery (как в предыдущих сценариях), мы применили таблицу стилей XSLT 2.0. Листинг 11 иллюстрирует часть нашего XSLT-кода.

Листинг 11. XSLT для частичного обновления сохраненного XML-документа
<xsl:param name="my:entityName" as="xs:string" />
<xsl:param name="my:tradeType" required="yes" as="xs:string" />
<xsl:param name="my:updateOrRestore" required="yes" as="xs:string" />
<xsl:param name="my:updatedScheduledTermination" as="node()" />

<xsl:variable name="updateCreditDefaultSwapURL"
    select="concat('jdbc://updateScheduledTerminationDateByEnityName?--XML--&', 
       $my:tradeType, '&', $my:entityName)" />

<xsl:when test="$my:updateOrRestore eq 'update'">
    <xsl:result-document href="{$updateCreditDefaultSwapURL}" method="xml" indent="yes">
    <xsl:copy-of select="$my:updatedScheduledTermination" />
  </xsl:result-document>
</xsl:when>

Объединение XML- и реляционных данных в новых XML-документах

Те Java EE-программисты, которые хотят получить только XML-представление реляционных и XML-данных на уровне базы данных, могут использовать поддержку частичного обновления документов DB2. Например, можно написать один оператор для обогащени XML-данных информацией, извлекаемой из реляционных столбцов таблицы, хранящейся в DB2, Oracle или другой СУБД. Эта возможность может оказаться полезной в различных ситуациях, поскольку она позволяет программистам совмещать XML- и реляционные данные из разных систем. Хотя этот сценарий не включен в пример кода для этой статьи, подход к исполнению такого запроса тот же, что и в предыдущих примерах.

Чтобы понять, как использовать поддержку частичного обновления документов DB2 таким способом, представьте себе, что наша база данных FpML включает традиционную реляционную таблицу, которая отслеживает контактную информацию регулярных участников торгов. Определение этой таблицы приведено в листинге 12.

Листинг 12. Создание таблицы FPMLADMIN.PARTYCONTACTINFO
CREATE TABLE FPMLADMIN.PARTYCONTACTINFO (
          PARTYID VARCHAR(40) PRIMARY KEY NOT NULL,
          PARTYNAME VARCHAR(100),
          PHONENO BIGINT,
          EMAILID VARCHAR(100),
          ADDRESS1 VARCHAR(100),
          ADDRESS2 VARCHAR(100),
          CITY VARCHAR(100),
          ZIPCODE BIGINT,
          STATE VARCHAR(100),
          COUNTRY VARCHAR(100)
     )

FpML-протоколы торгов часто включают в себя лишь ограниченную информацию об участниках торгов деривативами, однако для подтверждения сделок (контрактов) часто требуются более подробные сведения. Как показано в листинге 13, один оператор DB2 легко преобразует реляционные данные в XML-элементы, вставляет эти элементы в соответствующие узлы XML-документа и возвращает новый XML-документ для обработки.

Листинг 13. Обогащение FpML-протокола торгов реляционными данными
select xmlquery ('declare default element namespace "http://www.fpml.org/2009/FpML-4-7"; 
  transform 
  copy $new := $message 
  modify for $i in $new/FpML/party
  return
    do insert 
      db2-fn:sqlquery("select 
         XMLELEMENT(NAME ""ContactInfo"", 
         XMLELEMENT(NAME ""Address1"", p.ADDRESS1), 
         XMLELEMENT(NAME ""Address2"", p.ADDRESS2), 
         XMLELEMENT(NAME ""CITY"", p.CITY), 
         XMLELEMENT(NAME ""STATE"", p.STATE), 
         XMLELEMENT(NAME ""COUNTRY"", p.COUNTRY),
         XMLELEMENT(NAME ""PHONE"", p.PHONENO)
         ) 
         from FPMLADMIN.PARTYCONTACTINFO p 
         where partyId=parameter(1)", $i/partyId/text()) 
         as last into $i
         return <newroot>{$new}</newroot>'
  passing F.DOCUMENT as "message") 
FROM FPMLADMIN.FPML43 f  
where id=47022

Если реляционные данные хранятся в удаленной или OEM базе данных DB2, достаточно создать в своей базе псевдоним этой удаленной таблицы. Он отображает удаленные объекты базы данных на локальный сервер DB2 и позволяет программистам рассматривать эти удаленные объекты как локальные таблицы DB2. Таким образом, запрос из листинга 13 остается тем же, даже если исходные данные хранятся в удаленной DB2, Oracle или другой базе данных.

Кроме того, мы можем легко изменить этот запрос, вставив эти обогащенные данные о торгах в столбец XML нашей базы данных DB2. Все, что нам нужно сделать, это добавить предложение INSERT INTO. . . непосредственно перед предложением SELECT в листинге 13. (Если нужно сохранить оригинальный протокол торгов и вставить измененные записи в базу данных в качестве нового документа, можно проделать то же с запросом из листинга 9.)


Заключение

Во второй статье этого цикла мы показали, как программисты Java EE могут работать с XML на уровнях сервера приложений и сервера базы данных. В нескольких примерах приложений мы обработали большое количество временных и сохраненных XML-данных в серверном Java-приложении с применением возможностей индексации и фильтрации запросов как для XML-, так и для реляционных данных. В наших примерах также показано, как работать с подмножествами постоянных XML-данных – в частности, как извлечь только нужные XML-узлы из базы данных и как обновить только определенные XML-узлы в документе. Работа с фрагментами сохраненных XML-документов позволяет избежать лишней передачи данных между уровнями приложения и сервера баз данных, а также исключить обработку, которую в противном случае пришлось бы выполнять на сервере приложений. Наконец, мы показали, как соединять временные и постоянные XML-данные – требование, которое встречается все чаще благодаря популярности использования XML во многих компонентах современных программ.


Загрузка

ОписаниеИмяРазмер
Пример кода, использующего пакет XML-дополненийFpML-Sample-WASXMLFEP-DB2pureXML.zip5MB
Пример данных FpML и сценария для DB2fpmldb2was.zip2 МБ

Ресурсы

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=XML, Information Management, WebSphere
ArticleID=826241
ArticleTitle=Работа с XML на различных уровнях приложения: Часть 2. Создание эффективных приложений Java EE, использующих сервер базы данных XML
publish-date=07182012