首页 > Berkeley DB XML, 赵汝聪 > Berkeley DB Xml 入门系列之三: 使用Berkeley DB Xml Shell

Berkeley DB Xml 入门系列之三: 使用Berkeley DB Xml Shell

2009年8月24日 赵汝聪

1. 简介


Berkeley DB Xml Shell(以下简称DbXml Shell)是包含在发行包里的工具,可运行于UNIX家族平台(Linux, Solaris, HP-UX, Mac OS, Cygwin, AIX, FreeBSD…)和Windows平台上。DbXml Shell包含Berkeley DB XML的绝大多数常用功能,可以让我们在不编写一行代码的情况下,通过指令快速完成多种常用操作如创建/删除容器、插入/删除文档、查询、验证Query Plan等等,实为居家旅行必备佳品。要是在周五下午遭受紧急任务袭击,就更得靠它来拯救周末了。有时为了解决开发中遇到的问题,只要写一个非常简短的DbXml Shell脚本就可以实现预期功能或是重现环境,极大地提高了劳动生产率。

在使用DbXML shell之前,应当正确编译好Berkeley DB Xml库。具体编译过程请参考博客上的相关文章:

Berkeley DB Xml 入门系列之二: 在Linux下编译和使用Berkeley DB Xml

使用Visual C++ 2008 Express Edition 编译Oracle Berkeley DB XML

2. 运行


UNIX下的可执行文件为<dbxml>/install/bin/dbxml,Windows环境下为<dbxml>/bin/dbxml.exe。钻进DbXml Shell以前,先瞄一眼说明(中文是翻译的,发行版是E文的)

rucong@debian:~/dbxml/install/bin$ ./dbxml –?

选项:

-c 在-h选项所指定的路径中创建一个新的Berkeley DB环境。

-h <home> 使用指定的路径作为Berkeley DB环境(默认为当前路径)。

-P <password> 设置数据库的密码

-s <script> 执行一个或多个脚本文件

-t 打开事务功能(transaction mode)

-V 打印版本号

-v verbose模式,连用两次进入更详细的verbose模式.

-x 安全模式–禁止在XQuery中直接访问本地文件和网络

-z <size> 设置环境Cache大小为<size>Mb (默认: 64)

-? 本说明

3. 指令说明


进入shell:

rucong@debian:~/dbxml/install/bin$./dbxml

嗯,已经进入DbXml Shell环境了。还是请help为我们向导一下(嗯…中文是翻译的,发行版是E文的。排序是按名称的,名词是不译的。列出的是常用的,实际还有更多的)

# 注释符,在脚本中可用#来做注释
abort 取消当前事务
addAlias 为默认Container增加一个别名
addIndex 为默认Container增加一个Index
commit 提交当前Transaction,同时自动创建一个新Transaction
compactContainer 压缩Container
contextQuery 使用上一次查询结果作为上下文,可限定后续查询在已返回的结果中进行
cquery 在默认Container中进行查询,本指令和query的不同之处在于省略了显式collection()
createContainer 创建一个新的Container,并将其作为默认Container
delIndex 在默认Container中删除一条Index
getDocuments 获得Container里的所有文档
getMetaData 获得指定Document里的metadata
help 获得帮助信息。可以对某条指令进行特殊说明,如help putdocument
info 获得默认Container的信息
listIndexes 列出所有Index
lookupIndex 在默认Container中查找Index
lookupStats 在默认Container中查看Index状态
openContainer 打开一个Container并设置为默认Container
prepare 把指定的XQuery表达式预处理为默认Query表达式(default pre-parsed query),这样就可以快速地重复执行该Query
print 输出执行的结果,可输出到文件
putDocument 往Container里插入XML文档
query 执行指定的XQuery表达式,如无特殊指定,执行的就是prepare指令中预处理好的XQuery表达式
queryPlan 输出query plan。用来查看被优化后的表达式执行计划,同时可检查设置的Index是否生效
quit 退出程序。如果是用-s执行脚本文件,切记在结尾处加上这一句,不然程序会赖着不退出的
removeAlias 删除一个Container的别名
removeContainer 删除一个Container
removeDocument 在Container中删除一个Document
run 执行指定的脚本文件
setBaseUri 设置/获取 默认context的base URI
setLazy 设置Query为Lazy还是Eager
setMetaData 为指定的Document设置一个metadata
setNamespace 为默认Context创建一个"prefix->namespace"绑定
setQueryTimeout 设置Query的超时时间
setVerbose 设置Verbose级别
time 计时。可用来计算指令的执行时间
transaction 创建一个事务,用于所有后续操作
upgradeContainer 把老版本的XmlContainer升级到现版本

接下来让我们小试牛刀,运行几个常用命令试试:

创建一个空Container

dbxml> createcontainer ""

Creating node storage container

插入一个文档test.xml:

dbxml> putdocument test.xml ‘<root><a><b/></a></root>’

Document added, name = test.xml

看看文档插入了没:

dbxml> getdocuments

1 documents found

检查文档名称:

dbxml> printname

test.xml

检查文档内容:

dbxml> print

<root><a><b/></a></root>

做个简单查询,并计时:

dbxml> time query collection()/root/a

1 objects returned for eager expression ‘collection()/root/a’

Time in seconds for command ‘query’: 0.04848

输出查询结果:

dbxml> print

<a><b/></a>

退出

dbxml> print

<a><b/></a>

4.范例


上一节我们在DbXml Shell里做了一些简单的交互式操作,实际上我们采用DbXml Shell脚本更方便。下面是一个简单的DbXml Shell脚本,高级内容参见源代码包里的dbxml/docs/intro_xml/BerkeleyDBXML-Intro.pdf

createContainer "" #创建一个空Container

#插入一个文档

putdocument apples.xml ‘

<product>

<category>fruits</category>

<item>Apples</item>

<inventory>

<sku>Applfrui1q6lpq</sku>

<price>1.10</price>

<inventory>535</inventory>

</inventory>

<vendor>Off the Vine</vendor>

</product>

getdocuments #获得所有文档

printnames #输出文档名

print #输出文档内容

#使用XQuery查询价格,并计量查询时间

time query ‘collection()/product/inventory/price/string()’

echo "Price is:"

print

exit #退出

执行并输出结果:

rucong@debian:~/dbxml/install/bin$ ./dbxml -s example1.script

apples.xml

<product>

<category>fruits</category>

<item>Apples</item>

<inventory>

<sku>Applfrui1q6lpq</sku>

<price>1.10</price>

<inventory>535</inventory>

</inventory>

<vendor>Off the Vine</vendor>

</product>

Time in seconds for command ‘query’: 0.008049

Price is:

1.10

5.使用技巧

rlwrap是个好东西

UNIX用户初用DbXml Shell时,会悲愤地发现bash标配的命令行历史和左右箭头键居然统统废掉。呃…这意味着键入命令的过程中不能犯错,还不能重复历史指令,极不人道。因此该问题也凭借强大的怨念名列FAQ。其实只要使用rlwrap这个小工具便可以完美地解决这一问题(没有就装一个吧),rlwrap程序可以添加命令历史和命令编辑功能。用法:rlwrap ./dbxml。这体现了UNIX世界的哲学:把工具们连接在一起,而不是重复实现。

下面这条是OTN上荣列BestPractices的一条经验(作者是Greg Fausak):

/usr/bin/rlwrap -m -c -H ~/.rlhistory -l ~/dbxml.log -r -m -P ‘openC customer.dbxml \ adda L \ setN "test" "http://mytest.com/"’ /usr/local/bin/dbxml -h ~/sn/db

-H : 把命令执行历史存储在文件.rlhistory

-l : 把产生的所有的输入和输出存储在文件~/dbxml.log’

-m : 使能多行命令,和下面的-P选项连用。 -P "…" 里面的反斜杠\就是分行标识,用来分隔多个命令。

-P : 在执行操作前,自动输入一批指令。由于DbXml Shell可以执行脚本文件,所以总的说来rlwrap的"-m"和"-P"选项对我们用处不大,可以无视。

-h 这个是DbXml Shell的参数,指定Berkeley DB环境路径

创建一个临时Container

如果只是做个临时实验,不想大费周章地创建Container文件和DB环境,那么只需要创建一个名字为空的Container就行了。DbXml会在内存中创建一个临时的Container,有需要的话还可以用addAlias为这个空名Container增加别名。


不用输入完整指令

Shell会自动补完符合唯一性的指令:比如createc=createContainer,listi=listIndex…


修改Shell代码

Shell不是万能的,如果发现Shell的功能比实际需求就恰巧少了那么一点点,又不想从头编写一套C++/Java程序,那么就Open Source精神来武装头脑指导实践推动工作 — 杀进DbXml Shell源代码里面修改吧!Shell的源程序在dbxml/src/util/shell目录下,组织得非常规范,只要有初步DbXml编程经验就可以对Shell进行修改和增强。修改之后进入dbxml/build_unix,重新"make; make install"即可。Visual Studio环境下就更方便,重新编译Shell的Project就行了。比如OTN上曾有用户问如何用Shell获得整个Container的MetaData(Shell的getMetaData只能获得一个Document的MetaData),解决办法就是修改dbxml/src/utils/shell/GetMetaDataCommand.cpp,增加一条循环调用就行了。

  1. LEE
    2009年9月25日13:45 | #1

    看到的所有例程xml都是英文,如果是带中文字符的xml文档如何在BDB XML中来存储和检索

  2. 蔡瀛
    2009年9月25日18:14 | #2

    @LEE
    Berkeley DB XML内部使用UTF8编码存储文档的,你可以输入UTF8编码的中文。

  3. ecli
    2010年2月2日09:55 | #3

    我在Linux平台上使用dbxml 2.4.16.
    XQuery查询语句中包含中文,我试过将中文用GB2312和UTF8编码。程序在检索过程中都异常退出了。提示信息为:
    terminate called after throwing an instance of ‘DbXml::XmlException’
    what(): Error: nsFromUTF8: bad utf-8 encoding File: NsUtil.cpp Line: 249
    Aborted

    Teminal显示两种编码形式的查询语句,查询条件是event的值为“测试”。分别是:
    1.GB2312
    for $wholeXml in collection(‘EventsContainer.bdbxml’)/Video,$event in $wholeXml/EventName where (contains(“测试”, $event) return $wholeXml
    2.UTF8
    for $wholeXml in collection(‘EventsContainer.bdbxml’)/Video,$event in $wholeXml/EventName where (contains(“娴嬭瘯”, $event) return $wholeXml

    请问我该如何修正呢?

  4. 蔡瀛
    2010年2月8日17:35 | #4

    hi, 请问你是在程序中遇到这个错误还是在dbxml shell里面。 如果是shell, 你能不能把查询保存成一个utf8的文件,然后用shell去执行这个文件,看有没有错误。

  5. ecli
    2010年2月20日16:28 | #5

    @蔡瀛
    你好,我碰到的这个错误不是在dbxml shell里面,而是在程序中我通过调用类似以下的代码时出现的。querystring包含中文。

    XmlQueryContext context = _manager->createQueryContext();
    XmlResults res = _manager->query(querystring,context);

  6. ecli
    2010年2月20日17:50 | #6

    另外,我写了一个包含中文的存储例子,测试结果该记录不能被存入。
    string theDoc = “aac node”;
    XmlUpdateContext theContext = theManager.createUpdateContext();
    theContainer.putDocument( “”, theDoc, theContext, DBXML_GEN_NAME );

  7. 蔡瀛
    2010年2月21日10:27 | #7

    @ecli
    hi, 如果是程序的话你可能需要把源代码文件保存成utf8格式编译。在我的机器上环境是“zh_CN.UTF-8”, 保存中文查询中文都没有问题。

  8. ecli
    2010年2月22日18:35 | #8

    @蔡瀛
    按照你的建议把源代码文件保存成utf8格式编译。保存和查询中文已经没有问题了。谢谢~

  9. 天门冬
    2010年2月25日10:44 | #9

    Hi,你好。我写了一个多线程的例子来添加文档(通过DBXML.getInstance().insertXMLData(key);)。报出如下错误。单线程访问不会有问题,不知是哪里有问题?
    异常:
    com.sleepycat.dbxml.XmlException: Error: DB_LOCK_DEADLOCK: Locker killed to resolve a deadlock, errcode = DATABASE_ERROR
    at com.sleepycat.dbxml.dbxml_javaJNI.XmlContainer_putDocument__SWIG_7(Native Method)
    at com.sleepycat.dbxml.XmlContainer.putDocument(XmlContainer.java:917)
    at com.sleepycat.dbxml.XmlContainer.putDocument(XmlContainer.java:173)
    at com.wondersgroup.dbxml.DBXML.insertXMLData(DBXML.java:119)
    at com.wondersgroup.dbxml.InsertXmlData.run(InsertXmlData.java:46)
    2010-2-25 10:28:12 com.wondersgroup.dbxml.InsertXmlData run
    代码片段:
    public class DBXML {
    private static DBXML dbxml = null;
    private Environment environment;
    private XmlManager xmlManager;
    private XmlContainer xmlContainer;
    private DBXML() {
    setEnvironment();
    setXmlManager();
    setXmlContainer();
    }
    public static synchronized DBXML getInstance() {
    if (dbxml == null) {
    dbxml = new DBXML();
    }
    return dbxml;
    }
    public void setEnvironment() {
    System.out.println(“setEnvironment……”);
    File file = new File(“E:\\testing\\data”);
    EnvironmentConfig envConf = new EnvironmentConfig();
    envConf.setAllowCreate(true); // If the environment does not
    envConf.setInitializeCache(true); // Turn on the shared memory
    envConf.setInitializeLocking(true); // Turn on the locking subsystem.
    envConf.setInitializeLogging(true); // Turn on the logging subsystem.
    envConf.setTransactional(true);
    envConf.setLogInMemory(true);
    envConf.setLogBufferSize(30*1024*1024);
    envConf.setCacheSize(50*1024*1024);
    envConf.setLockDetectMode(LockDetectMode.DEFAULT);
    try {
    environment = new Environment(file, envConf);
    } catch (DatabaseException ex) {
    Logger.getLogger(DBXML.class.getName()).log(Level.SEVERE, null, ex);
    } catch (FileNotFoundException ex) {
    Logger.getLogger(DBXML.class.getName()).log(Level.SEVERE, null, ex);
    }
    }
    private void setXmlManager() {
    System.out.println(“setXmlManager……”);
    XmlManagerConfig managerConfig = new XmlManagerConfig();
    managerConfig.setAdoptEnvironment(true);
    managerConfig.setAllowAutoOpen(true);
    managerConfig.setAllowExternalAccess(true);
    try {
    xmlManager = new XmlManager(environment, managerConfig);
    } catch (XmlException ex) {
    Logger.getLogger(DBXML.class.getName()).log(Level.SEVERE, null, ex);
    }
    }
    private void setXmlContainer() {
    System.out.println(“setXmlContainer……”);
    XmlContainerConfig xmlContainerConfig = new XmlContainerConfig();
    xmlContainerConfig.setTransactional(true);
    xmlContainerConfig.setAllowCreate(true);
    xmlContainerConfig.setNodeContainer(true);
    xmlContainerConfig.setIndexNodes(true);
    try {
    if (xmlManager.existsContainer(“InstartXmlData.dbxml”) == 0) {
    xmlContainer = xmlManager.createContainer(“InstartXmlData.dbxml”, xmlContainerConfig);
    } else {
    xmlContainer = xmlManager.openContainer(“InstartXmlData.dbxml”, xmlContainerConfig);
    }
    } catch (XmlException ex) {
    Logger.getLogger(DBXML.class.getName()).log(Level.SEVERE, null, ex);
    }
    }
    public void insertXMLData(String key) {
    XmlTransaction xt = null;
    try {
    xt = xmlManager.createTransaction();
    XmlUpdateContext updateContext = xmlManager.createUpdateContext();
    XmlInputStream theStream = xmlManager.createInputStream(new FileInputStream(“E:\\testing\\source\\cdmdetails171.xml”));
    xmlContainer.putDocument(xt, key, theStream, updateContext, null);
    theStream.delete();
    xt.commit();
    } catch (FileNotFoundException ex) {
    Logger.getLogger(DBXML.class.getName()).log(Level.SEVERE, null, ex);
    } catch (XmlException ex) {
    Logger.getLogger(DBXML.class.getName()).log(Level.SEVERE, null, ex);
    if (xt != null) {
    try {
    xt.abort();
    } catch (XmlException ex1) {
    Logger.getLogger(InsertXmlData.class.getName()).log(Level.SEVERE, null, ex1);
    }
    }
    }
    }
    public void cleanup() {
    try {
    if (xmlContainer != null) {
    xmlContainer.close();
    }
    if (xmlManager != null) {
    xmlManager.close();
    }
    } catch (Exception ex) {
    ex.printStackTrace();
    }
    }
    }

  10. jianghua
    2010年5月11日16:09 | #10

    您好:
    我想问问有没有关于介绍Berkeley DB XML中对于XQuery是如何优化和执行方面的资料。谢谢

  11. jianghua
    2010年5月11日16:33 | #11

    您好:
    还有一个问题,在Shell命令下输入命令qplan然后接一个QXuery查询,显示出来的是什么?谢谢

  12. 蔡瀛
    2010年5月13日17:31 | #12

    @jianghua
    请查看《Getting Started with Berkeley DB XML》queryplan 那一小节

  13. czijian
    2010年9月1日17:54 | #13

    我最近在看dbxml,发现查询过程中没有找到类似MAX,MIN这样的语法,如果我想要查找一个某个包含最小值的项,只能使用类似下面的order,再获取第一条?
    std::string query = “for $item in collection(‘” + container.getName() + “‘)/fruits:item ”
    “for $inventory in $item/inventory/inventory ”
    “order by $inventory ”
    “return $item”;

    我在xquery下的grammer.cpp也没有找到类似的语法,那么dbxml到底能不能支持这样的操作?

  14. 蔡瀛
    2010年9月3日13:08 | #14

    DB XML 支持XQuery中的内建max函数, 具体请参考:
    http://www.w3.org/TR/xpath-functions/#func-max

本文的评论功能被关闭了.
Դ