设为首页 收藏本站
查看: 1046|回复: 0

[经验分享] DB2 XML 编程,第 2 部分: 在应用程序体系结构中使用 XML 数据库支持

[复制链接]

尚未签到

发表于 2016-11-17 08:24:33 | 显示全部楼层 |阅读模式
  简介
  XML 在数据库中的地位在过去两年中已经发生了变化,从 “临时工” 变成了重要成员。它不再需要改变本身来适应关系环境。它可以保持其层次化性质,同时利用关系数据库环境的功能和稳定性。实际上,一些关系性元素已经采用某些技术让它们看起来像 XML,以便利用层次化 XML 模型丰富的功能。
  本文讨论新的 XML 存储和查询环境如何处理本系列 第 1 部分 中的 XML 数据模型。还要说明,在采用新的基于 XML 的应用程序开发体系结构之后,数据库模式会变得更简单更自然。还演示如何按照在应用程序中查询数据的相同方式查询数据库中的 XML 数据。最后,讨论如何结合关系数据和 XML 数据,从而同时获得这两个环境的优势。
  XML 数据库基础
  尽管大多数主流关系数据库都有某种 XML 支持,但是 DB2 的 pureXML™ 支持要健壮和高效得多,这使它成为试验 XML 编程模型的理想数据库。本文主要关注如何在应用程序体系结构中使用新的 XML 数据库支持。
  DB2 允许存储、查询、操作和发布:


  • 关系数据 — SQL
  • 采用 XML 形式的关系数据 — SQL/XML
  • XML 数据 — XQuery
  • 混合型数据(关系数据和 XML 数据) — SQL/XML 和 XQuery
  
图 1. DB2 混合型存储
DSC0000.gif

  在数据库中存储 XML
  关系数据库中的 XML 支持的主要好处是,可以在同一个表中同时存储关系数据和 XML 数据。另外,尽管 XML 在内部存储为层次化(树)格式,但是它看起来像是存储在数据库表的单一列中(就像 CLOB 或 BLOB)。
  从第 1 部分中的数据对象可以看出,有两个表,每个表至少有两列。
  
清单 1. 表

DSC0001.gif CREATETABLECUSTOMER_TABLE(
CUSTOMERID
CHARACTER(12)NOTNULL,
CUSTXMLXML
NOTNULL,
CONSTRAINTCC1183665042494PRIMARYKEY(CUSTOMERID))

CREATETABLEPURCHASE_TABLE(
CUSTOMERID
CHARACTER(12)NOTNULL,
ITEMXMLXML
NOTNULL,
CONSTRAINTCC1183665244645FOREIGNKEY
(CUSTOMERID)
REFERENCESCUSTOMER_TABLE(CUSTOMERID)
ONDELETECASCADEONUPDATENOACTION
ENFORCEDENABLEQUERYOPTIMIZATION)




  显然,通过将应用程序的数据对象存储为 XML,关系模式大大简化了。另外,基础结构仍然是关系型的,这使 XML 数据能够利用关系数据库的实用功能,比如触发器、约束和外键关系。
  因为从逻辑上看 XML 列与 VARCHAR、CLOB 或 BLOB 列相似,所以 INSERT 语句也是相似的。

insertintoCUSTOMER_TABLEvalues('hardeep',
'<Customercustomerid="hardeep"firstname="hardeep"lastname="singh"/>')



  在 Java™ 程序中执行插入的代码也是相似的:
  
清单 2. 在 Java 程序中执行插入

Stringinsertsql="insertintoPURCHASE_TABLEvalues(?,?)";
PreparedStatementiStmt
=connection.prepareStatement(insertsql);
Fileinputfile
=newFile(filename);//filenameisthepathoftheXMLfile
longfilesize=inputfile.length();
BufferedReaderin
=newBufferedReader(newFileReader(inputfile));
iStmt.setCharacterStream(
1,in,(int)filesize);
intrc=iStmt.executeUpdate();



  为了更好地了解混合型存储,我们来看看 XML 数据的逻辑视图,体会 XML 数据如何看起来像是存储在关系数据库表中。
  注意:尽管不同关系数据库厂商的 XML 物理存储技术可能不一样,但是逻辑视图是相似的。
  
图 2. DB2 混合型存储逻辑视图
DSC0002.jpg

  查询 XML
  在展开数据库模式模型时,可以看到关系表和列。如果展开 XML 列,模式会从关系模型变成 XML 层次化模型。现在,您应该意识到其实有两个模式(一个关系模式和一个 XML 模式),但是把它们当作一个整体;理解了这一点,就能够以更自然的方式在这个统一的模式中进行导航和查询。
  对于清单 1 所示的统一模式,如果希望获得 CUSTOMER_TABLE 中 CUSTXML 列的数据,那么可以在查询中指定 CUSTXML 列的路径作为目标。

SELECTCUSTXMLFROMCUSTOMER_TABLEwherecustomerid='hardeep';



  这会返回 hardeep 的 CUSTXML 列中的客户数据。
  现在,考虑如何获得其 lastname 为 singh 的客户数据。在这种情况下,需要指定每个 XML 文档的 lastname 属性的路径(CUSTOMER_TABLE.CUSTXML/Customer/@lastname)并检查它是否是 singh。
  在完美的环境中,查询应该是 Select * from CUSTOMER_TABLE where CUSTXML/Customer/@lastname='singh'。但是在真实环境中,需要用数据库查询引擎能够理解的一种语法编写查询。数据库领域已经引入了一种称为 XQuery 的新语言,可以用它查询 XML 文档。SQL 添加了可以理解这种语言的新函数,从而将关系和 XML 环境联系起来了。所以搜索姓氏为 singh 的客户的查询如下:

selectCUSTXMLfromCUSTOMER_TABLE
wherexmlexists('$cust/Customer[@lastname="singh"]'passingCUSTXMLAS"cust")



  还可以在 Java 程序中通过参数化查询执行这个调用:

selectCUSTXMLfromCUSTOMER_TABLE
wherexmlexists('$cust/Customer[@lastname=$lname]'
passingCUSTXML
AS"cust",cast(?asVARCHAR(12))as"lname")



  掌握了向 SQL/XML 函数传递参数的语法之后,您会发现,在针对关系数据和 XML 数据的基本混合型查询中,XML 查询通常包含 XPath 表达式。这与在应用程序层中操作 XML 数据模型的方法非常相似(见第 1 部分),在那里许多代码通过对 Document Object Model(DOM)包装器进行 XPath 调用来查询和操作 XML 数据。
  注意:在 Viper 2 中,对传递给一些 SQL/XML 函数的参数做了简化。例如,在前面的查询中,XMLExists 的 passing 子句不需要指定 CUSTXML 列。

selectCUSTXMLfromCUSTOMER_TABLE
wherexmlexists('$CUSTXML/Customer[@lastname=$lname]'
passing
cast(?asVARCHAR(12))as"lname")



  将应用程序逻辑放在数据库中
  XQuery 提供了大多数高级语言的所有基本功能(if-then-else、for、变量、函数和算术操作符)。因此,可以将业务逻辑嵌入查询中。另外,它还提供许多常用的 XSLT 映射,所以它不但能够执行查询,还能够在数据库中转换 XML 输出。
  我们仍然以第 1 部分中 Customer 示例的 XML 数据模型为例。

<Customercustomerid=""firstname=""lastname="">
<Items><ItemID=""description=""purchaseDate=""price=""/></Items>
</Customer>



  用 DB2 查询替代应用程序代码
  我们不必在应用程序层中合并来自两个表的 XML 数据,可以在数据库中用一个 SQL/XML 查询实现相同的效果。这需要一个 CUSTOMER_TABLE.CUSTXML/Customer/@customerid 到 PURCHASE_TABLE.ITEMXML/Customer/@customerid 的一对多联结。
  
图 3. 联结两个 XML 列
DSC0003.jpg

  
清单 3. 查询两个 XML 列

values(xmlquery('

for$Customerindb2-fn:xmlcolumn("CUSTOMER_TABLE.CUSTXML")/Customer

where
$Customer/@customerid=$customerid

return
<Customercustomerid="{$Customer/@customerid}"
firstname
="{$Customer/@firstname}"lastname="{$Customer/@lastname}">{

for$Customer0indb2-fn:xmlcolumn("PURCHASE_TABLE.ITEMXML")/Customer
where
$Customer0/@customerid=$Customer/@customerid
return$Customer0/Item

}
</Customer>

'passingcast
(?ASvarchar(255))as"customerid"))



  对于客户 hardeep 购买的所有商品,产生的 XML 如下:
  
图 4. 查询结果
DSC0004.jpg

  在上面的查询中,必须构造外层的 Customer 元素并添加来自 CUSTXML 列数据的属性。DB2 Viper 2(beta)支持 XQuery 更新表达式,可以修改 XML 文档,所以不需要构造外层的 Customer 元素。可以使用来自客户表的一个 XML 文档,并将来自购买表的商品数据作为子元素插入其中。
  
清单 4. 针对两个 XML 列的 Viper 2 查询

values(xmlquery('

for$Customerindb2-fn:xmlcolumn("CUSTOMER_TABLE.CUSTXML")/Customer

let
$items:=(<Items>{

for$Customer0indb2-fn:xmlcolumn("PURCHASE_TABLE.ITEMXML")/Customer
where
$Customer0/@customerid=$Customer/@customerid
return$Customer0/Item

}
</Items>)

where
$Customer/@customerid=$customerid

return
transform
copy$cust:=$Customer
modify
(
doinsert$itemsaslastinto$cust)
return$cust

'passinghardeepas
"customerid"))



  在上面的查询中,不但搜索、获取和合并了数据库中存储的 XML 文档部分,还在产生的 XML 中添加了新元素。另外,hardeep 被隐式转换为 XML 类型(xs:string)。
  对比数据库查询和 Java 应用程序代码
  如果将上面的查询与第 1 部分中的 Java 代码(清单 6. 重写应用程序来使用 XML 模型)做一下对比,就会发现它们的逻辑非常相似。


  • 从 CUSTOMER_TABLE 中选择 Customer 信息。
  • 构造一个 Items 元素并在 PURCHASE_TABLE 中搜索这位客户购买的所有商品。
  • 循环遍历列表中的每个商品并将它们插入 Items 元素。
  • 将 Items 元素插入 Customer 元素。
  创建存储过程
  为了将数据库中的业务逻辑与应用程序代码隔离开,一种好方法是为这个查询创建一个存储过程。
  
清单 5. 创建存储过程

CREATEPROCEDUREcustomerItems(INcustidvarchar(12))
DYNAMICRESULTSETS
1
LANGUAGESQL
BEGIN
DECLAREc_curCURSORWITHRETURNFOR

values(xmlquery('

for$Customerindb2-fn:xmlcolumn("CUSTOMER_TABLE.CUSTXML")/Customer

let$items:=(<Items>{

for$Customer0indb2-fn:xmlcolumn("PURCHASE_TABLE.ITEMXML")/Customer
where$Customer0/@customerid=$Customer/@customerid
return$Customer0/Item

}</Items>)

where$Customer/@customerid=$customerid

return
transform
copy$cust:=$Customer
modify(
doinsert$itemsaslastinto$cust)
return$cust

'passingcustidas"customerid"))
OPENc_cur;
END



  用存储过程调用替代应用程序代码
  应用程序代码现在可以对 DB2 进行存储过程调用并将 XML 传递给 DOM 包装器。第 1 部分中的 XML 数据模型的应用程序代码(清单 6. 重写应用程序来使用 XML 模型,2-8 行)可以简化为:

2.ResultSetdbResult=dbstmt.executeQuery("callcustomerItems("+custid+")"
3.XMLParsecustomerXML=newXMLParse(dbResult.getString(1));



  一个更精细的示例
  现在考虑一个比较精细的场景,这个场景还要计算每个商品的保险费。为了让这个场景有点儿难度,保险费不但每天变动,而且随价格变化。这意味着,不但要向查询传递 customerid,还要传递保险费率。现在,假设您每天在保险公司提供的一个 Web 服务中查询最新的保险费率。保险费率信息采用 XML 文档的形式。

<insurance>
<rateprice="100"currency="$"rate=".02"/>
<rateprice="500"currency="$"rate=".018"/>
<rateprice=""currency="$"rate=".015"/>
</insurance>



  可以修改前面的存储过程来计算保险费。
  
清单 6. 计算每个商品的保险费的存储过程

CREATEPROCEDUREcustomerItemsWithInsurance(INcustidvarchar(12),rateXML)
DYNAMICRESULTSETS
1
LANGUAGESQL
BEGIN
DECLAREc_curCURSORWITHRETURNFOR

values(xmlquery('

for$Customerindb2-fn:xmlcolumn("CUSTOMER_TABLE.CUSTXML")/Customer

let$items:=(
<Items>{
for$Customer0indb2-fn:xmlcolumn("PURCHASE_TABLE.ITEMXML")/Customer

let$insurance:=<insurancecurrency="{($rate//rate[@price=""]/@currency)}">
{(
if($Customer0/Item/@price>500)then(
$Customer0/Item/@price*$rate//rate[@price=""]/@rate
)
else(

if($Customer0/Item/@price>100)then(
$Customer0/Item/@price*$rate//rate[@price="500"]/@rate
)
else(
$Customer0/Item/@price*$rate//rate[@price="100"]/@rate
)

)
)}</insurance>

where$Customer0/@customerid=$Customer/@customerid

return
transform
copy$item:=$Customer0/Item
modify(doinsert$insuranceaslastinto$item)
return$item
}</Items>
)

where$Customer/@customerid=$customerid

return
transform
copy$cust:=$Customer
modify(doinsert$itemsaslastinto$cust)
return$cust

'passingcustidas"customerid",rateas"rate"));

OPENc_cur;
END



  对这个存储过程的调用接受两个运行时参数,customerid 和保险 XML。
  



call customerItemsWithInsurance(?,?)



  显然,在上面的示例中,如果要操作的数据库数据是 XML 格式的,那么可以使用 XQuery 实现比只使用 SQL 时更多的业务逻辑。另外,查询中使用的 XML 甚至不需要在数据库中存在。因此,SQL/XML 查询中涉及的 XML 数据可以按照层次化形式存储在数据库中,可以由 SQL/XML 函数生成,甚至可以作为运行时参数传递给查询。数据库和应用服务器之间的差异逐渐变得模糊了。
  优点和缺点
  所有新技术在刚刚出现时都会有一些问题。一些问题是由于实现还不成熟造成的,其他问题是由于开发人员还不适应变化。


  • 尽管性能有所改进,但是仍然比不上关系数据。
  • XQuery 是一种新语言,而且一些 SQL/XML 函数的语法需要花时间适应。
  • 有许多遗留数据采用关系格式。
  • 最重要的是,这是一种创建业务应用程序和数据模式的新方式,它与当前的面向对象应用程序和规范化关系模式很不一样。
  • 能够对这类查询进行调试和优化的工具还不多。
  尽管存在这些缺点,但是新的模型管理数据的方式更加自然。在应用程序层和数据库层中都按原样维护和操作业务数据信息,而且您将第 3 部分中看到,甚至在客户机层中也是如此。


  • 尽管外围语言可能不一样(Java、XQuery、JavaScript、PHP),但是在所有层中用来在 XML 文档中移动的语言都是相同的(XPath)。
  • 即使遗留数据是关系型的,但是通过使用 Viper 2 中引入的一些 SQL/XML 函数,可以轻松地查询这些数据并将它们转换为 XML。看一下第 1 部分中的示例 “第二种情况 —— 所有数据在数据库中存储为关系形式”。可以使用 Viper 2 中引入的 XMLROW 函数简化这个查询。

    Select XMLROW (customerid, firstname, lastname OPTION as attributes ROW Customer)
    from customer_table where customerid=?



      还可以在关系数据和 XML 数据之间创建联结。在这个示例场景中,如果有第三个表,其中包含购买商品的产品说明,而且这是一个关系表,那么可以使用商品 ID 执行联结,从而获得购买的每种商品的产品说明。



    图 5. 联结关系列和 XML 列
    DSC0005.jpg



    Select details, weight from SQLPRODUCT, ITEM_TABLE
    where xmlexists ('$itemxml/item[@itemid=$pid]'
    passing ITEM_TABLE.ITEMXML AS "itemxml", SQLPRODUCT.PID AS "pid" )



      在 DB2 9 中,可以使用 passing 子句向 SQL 语句中嵌入的 XQuery 传递运行时参数,但是不能向 XQuery 中嵌入的 SQL 传递参数。在 Viper 2 中,这个限制已经消除了,现在可以向 XQuery 中嵌入的关系查询传递运行时变量。



    清单 7. 向 XQuery 中嵌入的 SQL 传递运行时变量

                            
    values(xmlquery('
    for $Customer0 in db2-fn:xmlcolumn("PURCHASE_TABLE.ITEMXML")/Customer
    where $Customer0/@customerid= $custid
    return (
    $Customer0/Item,
    db2-fn:sqlquery(
    ''select xmlrow(details, description, weight option ROW "description")
    from sqlproduct where pid= parameter(1)'', $Customer0/Item/@ID))
    ' passing cast( ? AS varchar(255) ) as "custid" ))



      因此,即使一部分数据位于关系表中,一些数据是 XML,现在都可以在 SQL 查询、XQuery 或这两者中在 XML 数据和关系数据之间进行动态联结。

  • 在某些情况下,性能可能不是大问题,因为:

    • 能够为数据库中存储的 XML 文档创建基于 XPath 表达式的索引。

      create index custfname on customer_table(info) generate key
      using xmlpattern '/Customer/@firstname' as sql varchar(64)


    • 因为数据库模式更简单,所以减少了所需的联结数量。
    • 因为现在可以在查询中缩减数据,然后再把数据发送给应用程序,所以可以减少 I/O。
    • 随时可以使用 SQL/XML 函数(比如 XMLTable)将 XML 文档中的关键信息提取到关系列中,并为它们创建关系索引。
    • 可以为 XML 文档创建文本搜索索引。


  结束语
  XML 已经取得了稳固的地位。大多数行业和政府组织都对他们的 XML 模式做了标准化,并要求电子文档必须符合这些模式。既然通过线路交换的 B2B 数据已经采用了 XML 格式,为什么不在数据库中按原样(pureXML)存储这些数据呢?将数据存储为 XML 之后,可以使用 XQuery 和标准的 SQL/XML 对它进行编制索引、查询、检验、操作、转换和更新。随着越来越多的应用程序逻辑被放在查询中,数据库可以以 Web 服务和 feed 的形式公开它的存储过程,从而成为面向服务体系结构(SOA)环境中活跃的参与者。
  “旧的秩序已经改变了,新的秩序正在形成。”(The old order changeth, yielding place to new.) Morte d'Arthur
  


  参考资料
  学习



  • 您可以参考本文在 developerWorks 全球站点上的 英文原文。
  • “ISV success with DB2 Viper”:准备将应用程序、例程和脚本迁移到 DB2 Viper。

  • 关于 DB2 XML 的技术文章:寻找更多关于 DB2 和 XML 的文章。
  • “DB2 Viper 快速入门”(developerWorks,2006 年 4 月):了解如何创建管理 XML 数据的数据库对象以及用 XML 数据填充 DB2 数据库。
  • “用 SQL 查询 DB2 XML 数据”(developerWorks,2006 年 4 月):了解如何用 SQL 和 SQL/XML 查询 XML 列中存储的 DB2 数据。
  • “使用 XQuery 查询 DB2 XML 数据”(developerWorks,2006 年 5 月):了解如何用 XQuery 查询 XML 列中存储的数据。

  • XML Programming with PHP and Ajax:在面向服务体系结构和其他业务场景中使用 DB2 9 的 XML 功能。
  • “结合使用 DB2 原生 XML 与 PHP”(developerWorks,2005 年 11 月):了解如何使用 DB2 Universal Database for Linux, UNIX, and Windows 的新版本中的本机 XML 功能简化应用程序代码和关系模式。
  • “Native XML Support in DB2 Universal Database”:对新的 DB2 XML 支持和传统关系数据库技术进行对比。

  • developerWorks China Information Management 专区:学习关于 DB2 的更多知识。在这里可以找到技术文档、how-to 文章、培训、下载、产品信息等等。
  • 随时关注 developerWorks 技术活动和网络广播。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-301399-1-1.html 上篇帖子: DB2数据库、DML数据操纵语言、DDL数据定义语言 下篇帖子: DB2中结构化类型和类型化表的管理
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表