1. Think in Berkeley Database Java Edition 概述

1. 什么是BDB?

BDB 的全称是Berkeley Database,是一种开源的嵌入式文本数据库。

它介于关系数据库与内存数据库之间,使用方式与内存数据库类似,因为它也是基于Key-Value形式存储,但它与内存数据库相比要更加强大。

强大在于有以下这些特性:

  • 一个高性能的Key-Value数据库,支持上百万的数据记录
  • 制约限制是硬件而不是它本身
  • 完整的ACID事务支持
  • 游标和二级索引支持
  • 交互式平台支持
  • 跨平台支持
  • 多线程支持
  • 支持日志
  • 数据备份与恢复
  • 支持RAM缓冲以减少频繁IO操作

当然它的强大不止于此,它甚至可以将对象直接存储到文件,并且建立一个一级索引和多个二级索引,根据我的理解,它在某种意义上应该也可以说是基于对象存储的一个数据库系统,因为它可以通过DPL直接将一个对象持久化到BDB数据库中。

2. BDB的历史发展

简单了解什么是BDB后,我们再来了解下它的发展历程。

BDB最早是由SyePyCAT软件从1996到2006的商业支持和开发。

这家公司于2006年2月被甲骨文公司收购,该公司继续开发和出售Berkeley DB。

Oracle的管理下,”Berkeley DB” 已成为三种不同的产品一个共同的品牌名称:

  1. Oracle Berkeley DB

  2. Berkeley DB java Edition

  3. Berkeley DB XML

这三种产品都有共同的祖先,目前正在积极发展。

当然,接下来我将重点讲述Berkeley DB Java Edition,因为正如前面我说的那样,
它可以将对象直接存储到文件,并且建立一个一级索引和多个二级索引,这种基于对象存储的数据库系统,性能将会是十分强大的。

3. 学习资源

3.1 使用下载

3.1.1 Maven 下载

我们暂且不使用最高版本,想获取最高版本下载配置请移步Maven仓库镜像查看

        <dependency>
            <groupId>com.sleepycat</groupId>
            <artifactId>je</artifactId>
            <version>5.0.73</version>
        </dependency>

3.1.2 Oracle 官网快速下载

Berkeley DB Java Edition (JE)

3.2 参考文档

3.2.1 官方参考文档

3.2.2 Berkeley DB Java Edition 中文翻译文档

Getting Started Guide 系列中文翻译列表:
BDB 入门篇 第1章 Berkeley DB Java Edition简介
BDB 入门篇 第2章 Database Environments
BDB 入门篇 第3章 Direct Persistence Layer First Steps
BDB 入门篇 第4章Working with Indices使用索引
BDB 入门篇 第5章 Saving and Retrieving Objects 保存和检索对象
BDB 入门篇 第6章 A DPL Example一个DPL 例子
附录:源码下载
Writing Transactional Applications 文档中文翻译列表
BDB 事务篇 第1章. Berkeley DB, Java Edition事务处理介绍
BDB 事务篇 第2章 Enabling Transactions 启用事务处理
BDB 事务篇 第3 章 Transaction Basics 事务处理基础
BDB 事务篇 第4章 Concurrency 并发
BDB 事务篇 第5章 备份和还原 Berkeley DB, Java Edition应用程序
BDB 事务篇 第6章 Summary and Examples 摘要和例子

3.2.3 其他博文

Berkeley DB Java Edition 原始API使用说明
BerkeleyDB Java Edition 注解API使用说明
BerkeleyDB Java Edition注解API使用源码
Java那些事之Berkeley DB
YoutuBe视频教程

4. 日志详解

我们再来了解下它的数据库存储文件结构和重要的日志介绍
BDB数据库文件概览

  • JE的日志文件跟其他的数据库的日志文件不太一样,跟C版的DBD也是有区别的
  • JE的日志文件只能APPEND,第一个日志文件名是 00000000.jdb,当他增长到一定大小的时候(默认是10M),开始写第二个日志文件00000001.jdb,已此类推。
  • 跟C版本有所不同,JE的数据日志和事务日志是放在一起的,而不是分开放的。
  • JE cleaner负责清扫没用到的磁盘空间,删除后,或者更新后新的记录会追加进来,而原有的记录空间就不在使用了,cleaner负责清理不用的空间。
  • 清理并不是立即进行的,当你关闭你的数据库环境后,通过调用一个cleaner方法来清理。
  • 清理也不是只动执行的,需要你自己手动调用cleaner 方法来定时清理的。
  • 日志文件的删除仅发生在检查点之后。cleaner准备出哪些log 文件需要被删除,当检查点过后,删掉一些不在被使用的文件。每写20M的日志文件就执行一次检查点,默认下。

注: *.jdb 是日志文件

关于数据库文件和日志文件

众所周知,传统的数据库文件和日志文件是分开存储的,但是在JE中数据库和日志并文件没有分开存储
相反,JE使用基于日志的存储系统来保护数据库的修改。 在对数据库进行任何更改之前,JE会将有关更改的信息写入日志文件。

5.常见异常

我们再来看下常见的异常,方便我们定位我们的程序Bug的解决。

Tips: 更多异常请参考译文中的内容或者等待我的博文更新。

6.代码实战

在java里头主要有两种使用方式,一种是基于注解DPL形式的,一种是基础的api使用。
DPL:Direct Persistence Layer 的简写,表示直接将对象持久化到数据库

6.1 Hello World 程序

接下来让我们写段代码来简单体验下它的基础用法。


import java.io.File;
import java.io.UnsupportedEncodingException;

import com.sleepycat.je.Database;
import com.sleepycat.je.DatabaseConfig;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.Environment;
import com.sleepycat.je.EnvironmentConfig;
import com.sleepycat.je.EnvironmentMutableConfig;
import com.sleepycat.je.LockMode;
import com.sleepycat.je.OperationStatus;

public class StudyEnvironmentConfigTest {

    // 配置数据库环境文件路径,
    private final static String BDB_ORGINAL_ENV_HOME_FILE_PATH = "original_env_home";
    private final static File BDB_ORGINAL_ENV_HOME_FILE = new File(BDB_ORGINAL_ENV_HOME_FILE_PATH);
    // 配置数据库文件名称
    private final static String BDB_FILE_NAME = "admin.db";

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        // -----------------------数据库环境----------------------------
        // 创建数据库环境引用
        Environment myEnvironment = null;

        // -----------------------数据库环境配置----------------------------
        // 创建数据库环境配置对象
        EnvironmentConfig myEnvironmentConfig = new EnvironmentConfig();
        // 以只读方式打开,默认为false
        myEnvironmentConfig.setReadOnly(false);
        // 设置该环境支持事务
        myEnvironmentConfig.setTransactional(true);
        // 当环境不存在的时候自动创建环境,默认为false
        myEnvironmentConfig.setAllowCreate(true);

        // 环境路径不存在则创建
        if (!BDB_ORGINAL_ENV_HOME_FILE.exists()) {
            BDB_ORGINAL_ENV_HOME_FILE.mkdirs();
        }

        // 创建数据库环境对象并加载数据库环境配置
        myEnvironment = new Environment(BDB_ORGINAL_ENV_HOME_FILE, myEnvironmentConfig);

        // 创建数据库环境多配置对象
        EnvironmentMutableConfig myEnvironmentMutableConfig = new EnvironmentMutableConfig();
        // 当提交事务的时候是否把缓存中的内容同步到磁盘中去。true 表示不同步,也就是说不写磁盘
        myEnvironmentMutableConfig.setTxnNoSyncVoid(false);
        // 当提交事务的时候,是否把缓冲的log写到磁盘上 true 表示不同步,也就是说不写磁盘
        myEnvironmentMutableConfig.setTxnWriteNoSyncVoid(false);
        // 设置当前环境能够使用的RAM占整个JVM内存的百分比
        myEnvironmentMutableConfig.setCachePercent(90);
        // 设置当前环境能够使用的最大RAM。单位BYTE
        myEnvironmentMutableConfig.setCacheSize(98304);

        myEnvironment.setMutableConfig(myEnvironmentMutableConfig);

        // 创建数据库配置对象
        DatabaseConfig myDatabaseConfig = new DatabaseConfig();
        // 设置该数据库支持事务
        myDatabaseConfig.setTransactional(true);
        // 如果数据库不存在就创建,默认为false
        myDatabaseConfig.setAllowCreate(true);
        // 以独占的方式打开,也就是说同一个时间只能有一实例打开这个database。
        myDatabaseConfig.setExclusiveCreate(false);
        // 只读方式打开,默认为false
        myDatabaseConfig.setReadOnly(false);

        // 创建数据库文件并加载数据库配置
        Database myDatabase = myEnvironment.openDatabase(null, BDB_FILE_NAME, myDatabaseConfig);

        System.out.println("-------------数据库环境配置信息Start---------------------------------");
        System.err.println("数据库环境配置信息:" + myEnvironment.getConfig());
        System.err.println("返回当前环境下的数据库列表:" + myEnvironment.getDatabaseNames());
        System.out.println("-------------数据库环境配置信息end---------------------------------");

        // 将aKey 和aData 放入数据库
        try {
            String aKey = "myFirstKey";
            String aData = "myFirstData";
            DatabaseEntry theKey = new DatabaseEntry(aKey.getBytes("UTF-8"));
            DatabaseEntry theData = new DatabaseEntry(aData.getBytes("UTF-8"));
            myDatabase.put(null, theKey, theData);
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        // 根据aKey 查找aData
        String aKey = "myFirstKey";
        try {
            DatabaseEntry theKey = new DatabaseEntry(aKey.getBytes("UTF-8"));
            DatabaseEntry theData = new DatabaseEntry();

            if (myDatabase.get(null, theKey, theData, LockMode.DEFAULT) == OperationStatus.SUCCESS) {
                byte[] retData = theData.getData();
                String foundData = new String(retData, "UTF-8");
                System.out.println("For key: '" + aKey + "' found data: '" + foundData + "'.");
            } else {
                System.out.println("No record found for key '" + aKey + "'.");
            }
        } catch (Exception e) {
            // Exception handling goes here
            e.printStackTrace();
            System.out.println("未知异常");
        }

        System.out.println("-------------数据库的配置信息Start---------------------------------");
        System.err.println(myDatabase.getConfig());
        System.out.println("取得数据库的名称:" + myDatabase.getDatabaseName());
        System.out.println("取得包含这个database的环境信息:" + myDatabase.getEnvironment());
        System.out.println("-------------数据库的配置信息end---------------------------------");

        // 如果数据库不为空
        if (myDatabase != null) {
            // 关闭数据库
            myDatabase.close();
        }
        // 关闭数据库环境
        if (myEnvironment != null) {
            // 在关闭环境前清理下日志
            myEnvironment.cleanLog();
            // 关闭数据库 环境
            myEnvironment.close();
        }
    }
}

本篇完~

猜你喜欢

转载自blog.csdn.net/hadues/article/details/80854288