首页 > Berkeley DB XML > Berkeley DB Xml 入门系列之一: 简介与”query”示例程序详解

Berkeley DB Xml 入门系列之一: 简介与”query”示例程序详解

2009年7月22日 蔡瀛 发表评论 阅读评论

Oracle Berkeley DB XML 是一个可嵌入的开源 XML 数据库(Embedded Native Xml Database),可基于 XQuery 访问存储在容器中的文档,并对其内容进行索引。Oracle Berkeley DB XML 构建于 Oracle Berkeley DB 之上,并继承了其丰富的特性和属性(包括 环境,各个级别的事务,Replication等)。与Oracle Berkeley DB 一样,它通过应用程序运 行,无需人为管理。Oracle Berkeley DB XML 主要功能模块包括有文档分析器、XML索引 器以及 XQuery 引擎,实现了最快速、最高效的Xml数据检索。

本文是Berkeley DB Xml入门系列文章的第一篇,此系列将会详细介绍Berkeley DB Xml的 使用和编程,并探讨一些Berkeley DB Xml 编程中的高级内容,欢迎大家关注。在这篇文章里面我们通过一个最简单查询例子,介绍最基本Berkeley DB Xml的编程流程,并介绍 Berkeley DB Xml 中的一些基本概念。

本示例程序(example/cxx/basic/query.cpp)使用C++编写,相应的Java版本可在安装包的example/java/basic目录下找到。

/*
*
*******
*
* 这是一个最简单的Berkeley DB Xml程序,描述了如何进行查询和结果处理
*
* 这个程序展示了以下几个方面内容:
*  初始化Berkeley DB Xml
*  创建XmlContainer
*  插入Xml文档
*  创建XQuery查询和执行查询
*  在查询中如何使用变量
*  结果处理
*
*
*/

#include <iostream>
#include <dbxml/DbXml.hpp>

using namespace DbXml;

int
main(int argc, char **argv)
{
    // 定义XmlContainer的文件名
    std::string containerName = "people.dbxml";
    // 定义Xml文档内容
    std::string content = "<people><person><name>joe</name></person><person><name>mary</name></person></people>";
    // 定义Xml文档名字,每个存储于XmlContainer中的Xml文档必须有唯一的名字
    std::string docName = "people";

    // 定义XQuery查询语句,用来查询姓名等于某个值的person结点, 注意$name是一
    // 个XQuery变量,可以赋值
    std::string queryString =
        "collection('people.dbxml')/people/person[name=$name]";

    try {

        // 所有的BDB XML程序都需要一个XmlManager对象,XmlManager用于管
        // 理BDB XML的各种对象资源
        XmlManager mgr;

        // 检查同名Xml容器是否已经存在了,存在的话就删除
        if (mgr.existsContainer(containerName))
            mgr.removeContainer(containerName);

        // 用XmlManager创建一个XmlContainer. Berkeley DB Xml把所有的Xml
        // 数据,索引以及其他相关内容存储在XmlContainer中,XmlContainer
        // 在磁盘上的表现就是一个.dbxml结尾的文件,当然也可以以其他后缀
        // 作为文件名结尾。我们也可以使用已经创建好的XmlContainer。
        XmlContainer cont = mgr.createContainer(containerName);

        // 修改container需要创建一个XmlUpdateContext对象
        XmlUpdateContext uc = mgr.createUpdateContext();
        // 插入一个Xml文档,提供文档名文档内容,和一个XmlUpdateContext对象
        // 插入后Xml文档就会以Berkeley DB Xml的格式存储于XmlContainer中
        cont.putDocument(docName, content, uc);

        // 如果是查询则需要创建一个XmlQueryContext对象
        XmlQueryContext qc = mgr.createQueryContext();

        // 可以在XmlQueryContext对象中设置需要查询的变量值
        qc.setVariableValue("name", "mary");

        // 接着创建一个XmlQueryExpression对象,用来进行查询,用前面创
        // 建的XmlQueryContext对象做为参数
        XmlQueryExpression expr = mgr.prepare(queryString, qc);
        // 执行查询,返回XmlResults对象
        XmlResults res = expr.execute(qc);

        // 可以通过XmlQueryExpression::getQuery()方法获得XQuery查询语句
        // 通过XmlResults::size()方法可以知道查询的结果集大小
        std::cout << "The query, '" << expr.getQuery() << "' returned " <<
            (unsigned int) res.size() << " result(s)" << std::endl;

        // 处理返回的XmlResults对象, 输出他们的值
        XmlValue value;
        std::cout << "Result: " << std::endl;
        while (res.next(value)) {
            std::cout << "t" << value.asString() << std::endl;
        }

        //异常处理, Berkeley DB Xml的所有对象如果发生异常会抛出XmlException
        } catch (XmlException &xe) {
            std::cout << "XmlException: " << xe.what() << std::endl;
    }
    return 0;
}

本程序的运行结果是:

[ying@ying build_unix]$ ./query
The query, 'collection('people.dbxml')/people/person[name=$name]' returned 1 result(s)
Result:
<person><name>mary</name></person>

总结

通过这个示例程序我们可以知道,Berkeley DB Xml的程序一般有一下几个步骤,创建XmlManager;创建或打开XmlContainer;创建XmlQueryExpression并执行查询;处理查询结果。读者可以尝试修改setc.setVariableValue(“name”, “mary”)这一句,看查询 结果是否有变化。更高级的Berkeley DB Xml程序可添加事务,环境(Berkeley DB 的Environment)等等功能, 读者可以关注本博客后续文章。

  1. 2009年7月22日17:23 | #1

    终于看到盼望已久的实例说明。我有几个问题请教:
    1. 是否有将BDB XML用于WEB应用服务端的实例(尤其基于是J2EE的)?;
    2. 如果要在服务端通过Java API访问 BDB XML,怎样将环境(事先创建好的BDB XML Environment)拷贝到Java Web应用的WEB-INF下使用?应该放在哪里?在Java程序中又该如何定位该环境(文件夹)?
    3. 查询操作通常按如下方式进行:
    XmlResults results = theMgr.query(fullQuery, context, null);
    //Iterate over the results of the query using an XmlValue object
    XmlValue value;
    while ((value = results.next()) != null){
    System.out.println(value.asString());
    }
    请问,查询结果XmlResults 类型是否有对应的Java类型,真希望直接返回给调用者并被其识别,而无需通过XmlValue迭代?

    以上3个问题,困扰我很久,特请教老师。

    非常感谢!!

  2. 蔡瀛
    2009年7月30日13:11 | #2

    @Jack
    谢谢你的关注,我把和你邮件交流结果贴在这里供其他同学参考
    1.Berkeley DB XML的Java用户大部分都是用于应用服务器端
    2.这个要参考具体的服务器编程文档,Tomcat的可以参考此处
    3.现在只能写代码把XmlValue转换成需要的类型,很多应用里面是这么做的

  3. Ken
    2009年8月6日13:42 | #3

    我用Java的api,并且用Lazy mode,query execute很快,在mm级,但是第一次hasNext()非常慢,需要一分钟以上
    ps:查询在1,000,000条数据范围内执行,加不加索引好像区别不大,不知道是否我索引加的不对。

  4. 蔡瀛
    2009年8月6日17:36 | #4

    @Ken
    Hi Ken, 麻烦你把你所建立的索引和部分文档片段发给我(ying.cai在oracle点com)看是否是索引建立的问题。另外你使用的XmlContainer的类型是什么(wholedoc or node)?

  5. 天门冬
    2009年8月10日15:26 | #5

    我在price节点添加了node-element-equality-double索引
    在查询时:
    1、collection(‘books.dbxml’)/bookstore[book/price = 100]速度很快,我查看了执行计划使用到了node-element-equality-double索引
    2、collection(‘books.dbxml’)/bookstore[book/price < 100]查询价格小于100时,速度很慢,而且执行计划里没有使用node-element-equality-double索引

    我想请教下,是不是小于的查询不会使用到索引?要怎么优化呢?

  6. 2009年8月10日22:25 | #6

    你好! 我是这个的初学,VS的MFC项目是不是不可以运行Berkeley DB Xml 的程序,我查找了很多网上的代码都是基于Win32的。

  7. 2009年8月11日21:19 | #7

    @黄
    已经解决..添加一个宏就OK了

  8. 蔡瀛
    2009年8月12日10:13 | #8

    @黄
    Hi, 能否把宏贴出来供大家参考?

  9. 蔡瀛
    2009年8月12日10:14 | #9

    @天门冬
    如果用Lazy的模式,速度应该不会慢。查询的速度和查询的结果集也有关系。至于为什么没有用到那个索引,我还要在研究一下,稍候回复你。

  10. 2009年8月12日13:31 | #10

    在 stdafx.h 中添加这段就OK了..
    我一个学长告诉我的..
    #ifdef DB_UNKNOWN
    #undef DB_UNKNOWN
    #endif
    #define DBTYPE MS_DBTYPE

  11. 天门冬
    2009年8月20日11:18 | #11

    Hi,你好!我想问下关于事务的问题
    我在程序中现在事务控制如下:
    1、配置容器支持事务
      XmlContainerConfig xcc = new XmlContainerConfig();
      xcc.setTransactional(true);
      xmlContainer = xmlManager.openContainer(“insertDBXML.dbxml”, xcc);
    2、打开一个事务
      x = xmlManager.createTransaction();
    3、添加或修改时使用此事务
      xmlContainer.putDocument(x, docName + “_” + i, docString, updateContext, null);
    4、提交事务
      x.commit();
    5、删除事务及容器
      if (x != null) {
        x.delete();
      }
      if (xmlContainer != null) {
        xmlContainer.close();
      }
      if (xmlManager != null) {
        xmlManager.close();
      }
    问题:1、这种控制方法每次都需要手动提交事务挺麻烦的,有没有类型事务代理的,如spring的事务?
    2、如果我有可能需要同时操作两个数据库的数据,就会有两个xmlManager。我该怎么来控制它们的事务呢?

  12. 蔡瀛
    2009年8月20日12:44 | #12

    @天门冬
    1. 有auto-commit的事务模式,可以参考《Getting Started with Berkeley DB XML Transaction Processing》auto commit那一节。
    2. 一个XmlManager 可以打开多个container。Transaction其实和XmlManager没有关系,多个Container只要在同一个Environment里面,对他们操作就可以使用同一个事务。

  13. 天门冬
    2009年8月21日09:42 | #13

    @蔡瀛
    你好,多个Container只要在同一个Environment里面的事务操作,好像可以了!
    如果有二个Environment的时候,该怎么处理好呢?
    在应用中会不会出现,有两个数据库放在不同的目录下,就会有两个Environment?

  14. 蔡瀛
    2009年8月21日15:36 | #14

    @天门冬
    Environment里面只是保存了一些锁,日志,region files等的信息,可以单独指定一个目录作为Environment这些文件的目录。多个Container放在哪个目录中没有关系,只要是在同一个Environment的环境下打开的,他们就会共享相同的这些Environment的设置。

    另外你上面说的一个Query不使用index的问题,确实是一个bug,在新版本中已经修复,谢谢你提交。如果你要在旧版本上使用index的话,可以用这样的查询:for $i in dbxml:lookup-index(“collection_name”,”price”)[.<500] return $i/../../bookstore

  15. 天门冬
    2009年9月2日16:27 | #15

    你好,Container在实际应用中的概念是什么,应该什么时候需要创建两个Container?
    如果我有两类的xml文档,是不是该创建两个Container呢,还是所有的文档放在一个Container中呢。

  16. 天门冬
    2009年9月3日10:44 | #16

    HI你好,我通过查询获得相应的结果集,我可以知道某个结果的key是什么吗?
    如:
    results = qe.execute(context);
    while (results.hasNext()) {
    XmlValue xmlValue = results.next();
    xmlValue.delete();
    }
    我可以知道xmlValue是属于哪个key的文档吗?

  17. 蔡瀛
    2009年9月3日17:40 | #17

    @天门冬
    Container是document的集合,不同类型的文档可以放在同一个container中,这取决于应用的需求。

  18. 蔡瀛
    2009年9月3日17:43 | #18

    @天门冬
    不知道你说的key是什么意思。虽然Berkeley DB Xml是建立在Berkeley DB上的,但是对Xml文档的存储不是简单的key和value形式。

  19. savez
    2009年11月24日20:42 | #19

    你好,我在windows下编译成功了,我想在win下进行测试,他那几个dll和lib改如何添加呀,还望老师赐教!

  20. 蔡瀛
    2009年11月25日10:21 | #20

    只要把编译出来的dll加到系统的path环境变量里面就可以了。如果是用VS编程的话,在项目设置里面可以添加lib。

  21. 小乐乐
    2009年11月26日15:04 | #21

    您好:下面是一个XML文件

    -
    -
    -
    Enterprise Architect
    2.5

    -
    -
    -

    -
    -

    -
    -
    -
    -
    -

    <UML:TaggedValue tag=”gentype” value=”" />

    -
    -

    <UML:TaggedValue tag=”gentype” value=”" />

    <UML:TaggedValue tag=”$ea_xref_property” value=”$XREFPROP=$XID={E18BACE2-31CC-4c19-901C-099455A08DF1}$XID;$NAM=Partitions$NAM;$TYP=element property$TYP;$VIS=Public$VIS;$PAR=0$PAR;$DES=@PAR;Name=state3;Size=40;@ENDPAR;@PAR;Name=state2;Size=40;@ENDPAR;@PAR;Name=state1;Size=40;@ENDPAR;$DES;$CLT={43BF6668-13D5-4a25-9CCE-4D553367A870}$CLT;$SUP=$SUP;$ENDXREF;” />

    -
    -
    -
    -
    -

    Destination” />

    -
    -

    -

  22. 小乐乐
    2009年11月26日15:09 | #22

    似乎我发的文件变成乱了,我想请问,用BDB XML解析XMI文件应该怎么处理呢,例如输出它的所有节点,我用如下的代码:
    #include “stdafx.h”

    #include
    #include

    using namespace DbXml;
    using namespace std;

    int main(int argc, char **argv)
    {

    // Get a manager object.
    XmlManager myManager;
    // Open a container
    XmlContainer myContainer =
    myManager.openContainer(“coffee-tea.dbxml”);
    // Get a query context
    XmlQueryContext context = myManager.createQueryContext();
    // Declare a namespace
    //context.setNamespace(“fruits”, “http://groceryItem.dbxml/fruits”);
    // Declare the query string. Find all the product documents
    // in the fruits namespace.
    std::string myQuery = “collection(‘coffee-tea.dbxml’)//*”;
    // Perform the query.
    XmlResults results = myManager.query(myQuery, context);
    // Show the size of the result set
    std::cout << “Found ” << results.size() << ” documents for query: ‘”
    << myQuery << “‘” << std::endl;
    // Display the result set
    XmlValue value;
    while (results.next(value)) {
    XmlDocument theDoc = value.asDocument();
    std::string docName = theDoc.getName();
    std::string docString = value.asString();
    std::cout << “Document ” << docName << “:” << std::endl;
    std::cout << docString << std::endl;
    std::cout << “===============================\n” <>a;
    return(0);

    }
    输出的结果是0,我的开发平台是VS2005,语言是C++

  23. 小乐乐
    2009年11月27日10:39 | #23

    a
    a
    a
    a
    a
    aEnterprise Architect
    a2.5
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a

    因为上面的xml是乱码,所以我在每行前面加了a,不过格式还是很乱,请问你们有没有邮箱可以让我把文件发过去?这样可以更好的说明问题,谢谢

  24. 小乐乐
    2009年11月27日10:40 | #24

    请问你们有没有邮箱可以让我把文件发过去?这样可以更好的说明问题,谢谢

  25. 小乐乐
    2009年11月27日10:41 | #25

    请问你们有没有邮箱可以让我把文件发过去?这样可以更好的说明问题,谢谢!

  26. 蔡瀛
    2009年11月27日10:50 | #26

    hi, 回复可能会屏蔽一些符号, 麻烦你把问题和代码发到 ying.cai在oracle.com(在替换成@).

  1. 本文目前尚无任何 trackbacks 和 pingbacks.
注意: 评论者允许使用'@user空格'的方式将自己的评论通知另外评论者。例如, ABC是本文的评论者之一,则使用'@ABC '(不包括单引号)将会自动将您的评论发送给ABC。使用'@all ',将会将评论发送给之前所有其它评论者。请务必注意user必须和评论者名相匹配(大小写一致)。
Դ