0x03 Berkeley DB XMl Java版之XmlManager 和 Containers

濮阳默
2023-12-01

1. Berkeley DB XMl Java版之XmlManager 和 Containers

虽然Containers(容器)是用于存储和管理XML文档的机制,但我们可以使用XmlManager对象来创建和打开XmlContainer对象。 因此,我们从XmlManager开始。

1.1 XmlManager

XmlManager是一个高级类,用于管理在BDB XML应用程序中使用的许多对象。

以下是我们可以使用XmlManager对象执行的一些操作:

  • 管理容器。 此管理包括创建,打开,删除和重命名容器
  • 创建用于将XML文档加载到容器中的输入流。
  • 创建XmlDocument和XmlQueryContext对象。
  • 准备并运行XQuery查询
  • 创建事务对象

因为XmlManager是构建重要BDB XML对象的唯一方法,所以它是BDB XML应用程序的核心。

1.1.2 Berkeley DB Environments

在您实例化XmlManager对象之前,您必须对Berkeley DB环境做出一些决定。 BDB XML要求您使用数据库环境。您可以显式使用环境,也可以允许XmlManager构造函数为您管理环境。

如果明确创建环境,则可以打开BDB XML中的重要功能,例如日志记录,事务支持以及对多线程和多进程应用程序的支持。它还为您提供磁盘上的位置来存储您的所有应用程序的容器。

如果允许XmlManager构造函数为您隐式创建和/或打开环境,则仅将环境配置为允许多线程共享环境和基础数据库(使用DB_PRIVATE)。环境未启用所有其他功能。

接下来的几节将介绍为了明确创建和打开环境而需要了解的内容。我们首先从这个活动开始,因为除了最简单的BDB XML应用程序之外,它可能是你将要做的第一件事。

1.1.2.1 Environment 配置属性

要使用环境,必须先打开它。 执行此操作时,您可以选择指定一系列配置属性。 这些具有启用重要子系统(例如事务支持)的效果。

有很多环境配置属性,这些属性在Berkeley DB文档中有所描述。 但是,您可能希望将其与BDB XML应用程序一起使用,因此我们在此处对其进行描述:

  • EnvironmentConfig.setAllowCreate()
    如果为true,并且在打开时环境不存在,则创建它。 尝试打开尚未创建的数据库环境是错误的。
  • EnvironmentConfig.setInitializeLocking()
    如果为true,则初始化锁定子系统。 当应用程序使用多个线程或同时读写Berkeley DB数据库的进程时,将使用此子系统。 在这种情况下,锁定子系统以及死锁检测器有助于防止并发读取器/写入器彼此干扰。

请记住,在BDB XML容器下使用Berkeley DB数据库,因此如果您希望容器可以被多个线程和/或多个进程访问,那么您应该启用此子系统。

  • EnvironmentConfig.setInitializeLogging()
    如果为true,则初始化日志记录子系统。 此子系统用于从应用程序或系统故障中恢复数据库。 有关正常和灾难性恢复的更多信息,请参阅“Berkeley DB XML事务处理入门”指南。
  • EnvironmentConfig.setInitializeCache()
    如果为true,则初始化共享内存池子系统。 该子系统是多线程BDB XML应用程序所必需的,它提供了一个内存缓存,可以由参与此环境的所有线程和进程共享。
  • EnvironmentConfig.setTransactional()
    如果为true,则初始化事务子系统。 该子系统为多个数据库访问操作提供原子性。 当事务正在使用时,如果事务中的任何给定操作发生错误,则可以进行恢复。 如果打开此子系统,则还必须打开日志记录子系统。

我们讨论在Berkeley DB XML Getting Started with Transaction
Processing指南中编写事务应用程序。

  • EnvironmentConfig.setRunRecovery()
    如果为true,则导致对基础数据库运行正常恢复。 正常恢复可确保数据库文件相对于日志文件中记录的操作保持一致。 例如,如果您的应用程序经历了非正常关闭,并且因此某些写入操作可能未刷新到磁盘,则此功能非常有用。

只有在打开日志记录子系统时才能运行恢复。 此外,恢复只能由单个控制线程运行; 通常,在执行任何其他数据库操作之前,它由应用程序的主线程运行。

无论您决定在创建时设置哪些属性,在所有后续环境打开时使用相同的属性都很重要(例外情况是EnvironmentConfig.setAllowCreate(),只需创建环境)。 特别是,请避免使用属性来打开创建时未使用的环境。 这是因为不同的子系统在磁盘上需要不同的数据结构,因此尝试使用在首次创建环境时未初始化的子系统是非法的。

1.1.2.2 打开和关闭 Environments

要使用环境,必须先打开它。 在打开时,您必须确定它所在的目录,并且该目录必须在打开尝试之前存在。 在开放时,您还可以指定要用于您的环境的open(如果有)。

完成环境后,必须确保它已关闭。 您可以显式执行此操作,也可以让XmlManager对象为您执行此操作。

如果要明确关闭环境,则必须确保在关闭环境之前已关闭环境中打开的所有容器。 此外,在这种情况下,为确保应用程序关闭您的环境,您应该在应用程序的顶级try块的finally块中执行此活动。

package dbxml.gettingStarted;

import com.sleepycat.db.DatabaseException;
import com.sleepycat.db.Environment;
import com.sleepycat.db.EnvironmentConfig;
import com.sleepycat.dbxml.XmlException;

import java.io.File;

class doDbXml {
    public static void main(String args[]) throws Throwable {
        Environment myEnv = null;
        File envHome = new File("/export1/testEnv");

        // Open an XmlManager
        try {
            //创建一个环境对象配置
            EnvironmentConfig envConf = new EnvironmentConfig();
            //添加环境对象配置属性
            // 如果环境不存在就创建它
            envConf.setAllowCreate(true);
            //打开共享缓存
            envConf.setInitializeCache(true);
            //打开锁系统
            envConf.setInitializeLocking(true);
            //打开日志系统
            envConf.setInitializeLogging(true);
            //打开事务系统
            envConf.setTransactional(true);
            //设置自定义异常处理
            MyErrorHandler meh = new MyErrorHandler();
            envConf.setErrorHandler(meh);
           
            //初始化环境
            myEnv = new Environment(envHome, envConf);

        } catch (XmlException e) {
            // Error handling goes here
        }finally {
            //如果数据库环境不为空
            if(myEnv!=null){
                try {
                    //尝试关闭数据库环境
                    myEnv.close();
                } catch (DatabaseException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

1.1.3 XmlManager实例化和销毁

我们可以通过调用其构造函数来创建XmlManager对象。 您通过调用其close()方法来销毁XmlManager对象。

请注意,关闭XmlManager并在关闭对象的最后一个打开句柄时释放其所有资源。

要构造XmlManager对象,您可能会也可能不会为构造函数提供打开的Environment对象。

如果使用打开的环境句柄实例化XmlManager,那么如果将XmlManagerConfig ::
setAdoptEnvironment()设置为true,XmlManager将关闭并销毁该Environment对象。

如果为构造函数提供Environment对象,则可以使用该对象来使用应用程序可能需要的任何子系统

如果您不提供环境对象,则XmlManager将隐式为您创建环境。

在这种情况下,环境将不会配置为使用任何子系统,并且只能由同一进程内的多个线程共享。此外,在这种情况下,您可以使用以下机制之一选择性地标识容器所在的磁盘位置:

  • 在容器名称中指定磁盘位置的路径。
  • 使用DB_HOME环境变量指定环境的数据位置。

在任何一种情况下,您都可以向XmlManager构造函数传递一个XmlManagerConfig对象,该对象控制该对象关于底层容器的行为(该属性不会直接传递给底层环境或数据库)。 配置方法是:

  • XmlManagerConfig.setAllowAutoOpen()
    如果设置为true,则XQuery查询引用已创建但未打开的容器将自动导致在查询期间打开容器。
  • XmlManagerConfig.setAdoptEnvironment()
    如果设置为true,XmlManager将关闭并销毁在XmlManager关闭时实例化的Environment对象。
  • XmlManagerConfig.setAllowExternalAccess()
    如果设置为true,则从BDB XML内部执行的XQuery查询可以访问外部源(URL,文件等)。

1.1.3.1 使用默认环境实例化XmlManager

package dbxml.gettingStarted;

import com.sleepycat.dbxml.XmlException;
import com.sleepycat.dbxml.XmlManager;

class doDbXml {
    public static void main(String args[]) throws Throwable {
        XmlManager myManager = null;
        try {
            myManager = new XmlManager();
        } catch (XmlException e) {
            // Exception handling goes here
        } finally {
            try {
                if (myManager != null) {
                    myManager.close();
                }
            } catch (XmlException ce) {
                // Exception handling goes here
            }
        }
    }
}

1.1.3.2 使用显式环境对象实例化XmlManager

package dbxml.gettingStarted;

import com.sleepycat.db.DatabaseException;
import com.sleepycat.db.Environment;
import com.sleepycat.db.EnvironmentConfig;
import com.sleepycat.dbxml.XmlException;
import com.sleepycat.dbxml.XmlManager;
import com.sleepycat.dbxml.XmlManagerConfig;

import java.io.File;

class doDbXml {
    public static void main(String args[]) throws Throwable {
        Environment myEnv = null;
        File envHome = new File("/export1/testEnv");

        // Open an XmlManager
        XmlManager myManager=null;
        try {
            //创建一个环境对象配置
            EnvironmentConfig envConf = new EnvironmentConfig();
            //添加环境对象配置属性
            // 如果环境不存在就创建它
            envConf.setAllowCreate(true);
            //打开共享缓存
            envConf.setInitializeCache(true);
            //打开锁系统
            envConf.setInitializeLocking(true);
            //打开日志系统
            envConf.setInitializeLogging(true);
            //打开事务系统
            envConf.setTransactional(true);
            //设置自定义异常处理
            MyErrorHandler meh = new MyErrorHandler();
            envConf.setErrorHandler(meh);

            //初始化环境
            myEnv = new Environment(envHome, envConf);

            XmlManagerConfig managerConfig = new XmlManagerConfig();
            managerConfig.setAdoptEnvironment(true);
            myManager = new XmlManager(myEnv, managerConfig);

        } catch (XmlException e) {
            // Error handling goes here
        }finally {
            if(myManager!=null){
                try {
                    myManager.close();
                } catch (XmlException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

1.2 管理Containers(容器)

在BDB XML中,我们将XML文档存储在容器中。 容器是磁盘上的文件,其中包含与文档关联的所有数据,包括元数据和索引。

要创建和打开容器,请使用XmlManager.createContainer()。 创建容器后,您不能再次使用createContainer() 相反,只需使用以下命令打开它:XmlManager.openContainer()

请注意,我们可以使用XmlManager.existsContainer()方法测试容器是否存在。 此方法应在封闭容器上使用。 如果指定的文件不是BDB XML容器,则返回0。 否则,它返回基础数据库格式编号。

或者,我们可以通过调用openContainer()来创建和打开容器,并将其传递给必要的属性以允许创建容器.

您可以多次打开容器。 每次打开容器时,都会收到该容器的引用计数句柄。

我们通过调用XmlContainer.close()关闭容器。 请注意,在关闭容器的最后一个句柄之前,容器实际上并未关闭。

package dbxml.gettingStarted;

import com.sleepycat.dbxml.XmlContainer;
import com.sleepycat.dbxml.XmlException;
import com.sleepycat.dbxml.XmlManager;

import java.io.FileNotFoundException;

public class doDbXml{
    public static void main(String args[]){
        XmlManager myManager = null;
        XmlContainer myContainer = null;
        XmlContainer myContainer2 = null;
        try {
            myManager = new XmlManager();
            // Open the container. If it does not currently exist,
            // then create it.
            myContainer = myManager.createContainer("/export/xml/myContainer.bdbxml");

            // Obtain a second handle to the container. This container is closed
            // when its last handle is closed.
            myContainer2 = myManager.openContainer("/export/xml/myContainer.bdbxml");

        } catch (XmlException e) {
            // Exception handling goes here
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                if (myContainer != null) {
                    myContainer.close();
                }

                if (myContainer2 != null) {
                    myContainer2.close();
                }

                if (myManager != null) {
                    myManager.close();
                }
            } catch (XmlException ce) {
                // Exception handling goes here
            }
        }

    }
}

1.2.1 Container(容器)属性

创建或打开容器时,可以指定大量属性来控制容器行为的各个方面。 以下是BDB XML应用程序常用的属性。

  • XmlContainerConfig.setAllowCreate()
    导致创建容器和所有基础数据库。 没有必要在调用XmlManager.createContainer()时指定此属性。 此外,您需要为XmlManager.openContainer()指定它。 仅当尚未创建容器时。
  • XmlContainer.setExclusiveCreate()
    如果容器已存在,则导致容器创建失败。 没有必要在调用XmlManager.createContainer()时指定此属性。 请注意,除非同时使用XmlContainerConfig.setAllowCreate(),否则此属性无意义。
  • XmlContainerConfig.setReadOnly()
    打开容器仅供读取访问。
  • XmlContainerConfig.setAllowValidation()
    导致文档在加载到容器中时进行验证。 默认行为是不验证文档。
  • XmlContainerConfig.setIndexNodes()
    • 确定容器的索引是否将返回节点(如果此属性设置为“开”)或文档(如果此属性设置为“关”)。
    • 请注意,默认索引类型由您正在创建的容器类型决定。 如果要创建NodeContainer类型的容器,则默认情况下此属性设置为On。 对于WholedocContainer类型的容器,默认情况下此属性设置为Off。
    • 如果要在现有容器上更改此属性,则必须重新索引容器,以使新索引类型生效。
  • XmlContainerConfig.setTransactional()
    容器支持事务。 有关更多信息,请参阅Berkeley DB XML事务处理入门指南。

1.2.2 Container(容器)类型

在创建时,每个容器都必须具有为其定义的类型。 此容器类型标识XML文档如何存储在容器中。 因此,容器类型只能在容器创建时确定; 您无法在后续容器打开时更改它。

容器可以为它们指定以下类型之一:

  • WholedocContainer
    容器包含整个文件; 文档按“原样”存储,不需要任何换行符或空格。 要使容器保存整个文档,请将XmlContainerConfig.setNodeContainer()设置为false。
  • NodeContainer
    • XmlDocuments存储为容器中的单个节点。 也就是说,底层数据库中的每条记录都包含一个叶子节点,其属性和属性值(如果有)及其文本节点(如果有)。 BDB XML还保留了从存储在底层数据库中的各个节点重新组装文档所需的信息。
    • 这是默认的首选容器类型。
    • 要使文档存储为单个节点,请将XmlContainerConfig.setNodeContainer()设置为true。
  • 默认的容器类型
    使用默认容器类型。 您可以使用XmlManager.setDefaultContainerType()设置默认容器类型。 如果您从未设置默认容器类型,则容器将使用节点级存储。

请注意,NodeContainer的查询速度通常比WholedocContainer快。
另一方面,与NodeContainer相比,WholedocContainer为容器提供了更快的文档加载时间,因为BDB XML不必将文档解构为其各自的叶节点。 出于同样的原因,出于同样的原因,WholedocContainer更快地检索整个文档 -文档不必重新组装。

因此,除非满足下列条件之一,否则应使用NodeContainer

  • 负载性能对我们来说比查询性能更重要。
  • 我们希望经常检索整个XML文档(而不仅仅是文档的一部分)。
  • 我们的文档太小,以至于NodeContainer提供的查询优势可以忽略不计或完全消失。 达到此阈值的大小当然取决于应用程序可用的物理资源(内存,CPU,磁盘速度等)。

请注意,如果我们的文档大小超过兆字节,则应避免使用WholedocContainerWholedocContainer针对小型文档进行了调整,随着文档量的增大,您将承担越来越多的性能损失。

package dbxml.gettingStarted;

import com.sleepycat.dbxml.XmlContainer;
import com.sleepycat.dbxml.XmlException;
import com.sleepycat.dbxml.XmlManager;

import java.io.FileNotFoundException;

public class doDbXml {
    public static void main(String args[]){
        XmlManager myManager = null;
        XmlContainer myContainer = null;
        try {
            myManager = new XmlManager();
            myManager.setDefaultContainerType(XmlContainer.WholedocContainer);

            // Create and open the container.
            myContainer = myManager.createContainer("/export/xml/myContainer.bdbxml");

        } catch (XmlException e) {
            // Exception handling goes here
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                if (myContainer != null) {
                    myContainer.close();
                }
                if (myManager != null) {
                    myManager.close();
                }
            } catch (XmlException ce) {
                // Exception handling goes here
            }
        }
    }
}

1.2.3 删除和重命名Container(容器)

您可以使用XmlManager.removeContainer()删除容器。 尝试删除打开的容器是错误的。

您可以使用XmlManager.renameContainer()重命名容器。 尝试重命名打开的容器是错误的。

package dbxml.gettingStarted;

import com.sleepycat.dbxml.XmlException;
import com.sleepycat.dbxml.XmlManager;

import java.io.FileNotFoundException;

public class doDbXml2 {
    public static void main(String args[]){
        XmlManager myManager = null;
        try {
            myManager = new XmlManager();

            String currentName = "/export/xml/myContainer.bdbxml";
            String newName = "/export2/xml/myContainer.bdbxml";

            myManager.renameContainer(currentName, newName);

            myManager.removeContainer(newName);

        } catch (XmlException e) {
            // Exception handling goes here
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                if (myManager != null) {
                    myManager.close();
                }
            } catch (XmlException ce) {
                // Exception handling goes here
            }
        }
    }
}
 类似资料: