Berkeley DB(BDB)是一个高效的嵌入式数据库编程库,C语言、C++、Java、Perl、Python、Tcl以及其它非常多语言都有其相应的API。

Berkeley DB能够保存随意类型的键/值对(Key/Value Pair),并且能够为一个键保存多个数据。Berkeley DB支持让数千的并发线程同一时候操作数据库。支持最大256TB的数据。广泛用于各种操作系统,当中包含大多数类Unix操作系统、Windows操作系统以及实时操作系统。

Berkeley DB在06年被 Oracle 收购了。如今我们在 Oracle 站点上会看到: BerkeleyDB、BerkeleyDB XML 和 BerkeleyDB JAVA Edition 这个三个东东。

简单的说最開始 BerkeleyDB 是仅仅有 C 语言版本号的,可是 JAVA 也能够使用。仅仅只是须要通过 JNI 调用,效率可能有点影响。后来出了 JAVA Edition 。用纯 JAVA 实现了一遍,也就是我们看到的 BerkeleyDB JAVA Edition (简称 JE )。

JE是一个通用的事务保护的,100%纯Java(JE不作不论什么JNI调用)编写的嵌入式数据库。因此。它为Java开发者提供了安全高效的对随意数据的存储和管理。



JE 适合于管理海量的,简单的数据。当中的记录都以简单的键值对保存,即key/value对。因为它操作简单,效率较高,因此受到了广泛的好评。

JE官网:http://www.oracle.com/technetwork/database/database-technologies/berkeleydb/overview/index.html

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbG9uZ3p1eXVhbg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast">

一些特性:

1. 大型数据库的支持:它支持从1到数百万级的数据量。数据库的限制大小基本上受限于你的硬件支持。

2. 多线程,多进程支持:JE读写操作都能够是多线程,使用记录级锁定为线程应用程序提供高并发性。此外,JE使用死锁超时检測的机制来确保不会有两个线程无限期的死锁。

JE同意多个进程訪问同一个DB。但在这样的情况下, Berkeley 仅仅同意一个线程进行写操作,读操作任意。

3. 事务:原子性,可恢复,隔离性。

4. 内存Cache:为了降低IO操作提高性能,将数据暂存在内存里面。

5. 索引。

简单读写操作:

Database.put(): 向数据库写入数据,假设不支持反复记录,则会覆盖更新key相应的已有记录

Database.putNoOverwrite():向数据库写入数据,可是假设key已经存在,不会覆盖已有数据(即使数据库支持反复key)

Database.putNoDupData():向数据库写入数据(该方法仅用于支持反复key的数据库),假设key和value相应的记录已经存在,那么操作结果是:OperationStatus.KEYEXIST

Database.get() :检索key相应的记录,假设没有找到,操作结果返回:OperationStatus.NOTFOUND

Database.getSearchBoth() :依据key和value 检索数据库记录,假设没有找到,操作结果返回:OperationStatus.NOTFOUND

属性配置

跟Environment一样,database也能够通过DatabaseConfig进行配置。

DatabaseConfig.setAllowCreate()

设置当不存在该数据库的时候是否创建一个新的库

DatabaseConfig.setBtreeComparator()

设置用来决定数据库中记录顺序的排序器

DatabaseConfig.setDuplicateComparator()

设置用来比較反复数据的排序器

DatabaseConfig.setSortedDuplicates()

设置该数据库是否同意反复的数据

DatabaseConfig.setExclusiveCreate()

设置当存在该数据库的时候是否会打开数据库失败

DatabaseConfig.setReadOnly()

设置数据库是否仅仅读

DatabaseConfig.setTransactional()

设置事务属性

DatabaseConfig.setDeferredWrite()

设置延迟写属性

DatabaseConfig.setTemporary()

设置该数据库是否为暂时数据库(Temporary Databases)

延迟写数据库

默认情况下。数据库会在操作的时候写入变化到磁盘中,假设你使用了事务。那么将会在事务提交的时候写入变化。

可是假设你启用了延迟写配置,数据库不会把变化马上写入,除非1.显式的调用了Database.sync()方法;2.缓存满了;3.到达了检查点(checkpoint)。


延迟写能够带来下面两个优点:

1.在多线程情况下,能够降低写操作的瓶颈。

2.能够降低写操作数据库,比方你一条记录你多次改动了它,那仅仅会最后一次的改变会被写入到数据库中。

数据库也能够在延迟写和普通库之间进行转换,比方你要载入非常大量的数据到数据库中,明显的延迟写数据库相较于普通数据库有更好的性能,这时你能够在载入大数据的时候设置延迟写,在载入完成之后一次性的写入到数据库中。然后关闭数据库。再使用普通数据库配置属性打开。


设置DatabaseConfig.setDeferredWrite(true)。能够让数据库变成延迟写数据库。

暂时数据库

这是一个非常特殊的数据库。打开暂时数据库后,你能够像一般的数据库一样对它进行操作,可是在关闭这个数据库后全部的数据将被清除。

也就是说暂时数据库中的数据不是持久性的。


而且暂时数据库内部採用了延迟写,可是这并不意味着暂时数据库将不会发生I/O操作。当缓存满的时候,数据库仍然会把数据写入到磁盘上。

暂时数据库拥有延迟写数据库的全部长处。可是有一点不同于延迟写数据库,它不会在到达检查点的时候进行写入。

设置DatabaseConfig.setTemporary(true),能够让数据库变成延迟写数据库。

//URL队列的实现,讲訪问过的URL存到另外一个数组中。并删除队列中已经訪问过的URL

package com.mycrawler.berkeleydb;

import java.io.File;

import com.sleepycat.je.Cursor;
import com.sleepycat.je.Database;
import com.sleepycat.je.DatabaseConfig;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.Environment;
import com.sleepycat.je.EnvironmentConfig;
import com.sleepycat.je.LockMode;
import com.sleepycat.je.OperationStatus;
import com.sleepycat.je.Transaction; public class OperatingDB {
//讲URL写入队列中
public boolean writerURL(String fileName, String url,
String databaseDBName, String rankPage) {
boolean mark = false;
// 配置环境 https://community.oracle.com/thread/996592?start=0&tstart=0 问题地址
EnvironmentConfig envConfig = new EnvironmentConfig(); // 设置配置事务
envConfig.setTransactional(true);
// 假设不存在就创建环境
envConfig.setAllowCreate(true);
File file = new File(fileName);
file.mkdirs();
try {
Environment exampleEnv = new Environment(file, envConfig); Transaction txn = exampleEnv.beginTransaction(null, null); DatabaseConfig dbConfig = new DatabaseConfig();
dbConfig.setTransactional(true);
dbConfig.setAllowCreate(true);
dbConfig.setSortedDuplicates(false);
Database exampleDb = exampleEnv.openDatabase(txn, databaseDBName,
dbConfig);
txn.commit();
DatabaseEntry theKey = new DatabaseEntry(url.getBytes("utf-8"));
DatabaseEntry theData = new DatabaseEntry(
rankPage.getBytes("utf-8"));
exampleDb.put(null, theKey, theData);
exampleDb.close();
exampleEnv.close();
} catch (Exception e) {
e.printStackTrace();
mark = false;
} return mark;
} // 读取没有訪问过的URL
public String readerURL(String fileName, String databaseDBName) {
// boolean mark = false;
// 配置环境
EnvironmentConfig envConfig = new EnvironmentConfig();
// 设置配置事务
envConfig.setTransactional(true);
// 假设不存在就创建环境
envConfig.setAllowCreate(true);
File file = new File(fileName);
String theKey = null;
// file.mkdirs();
try { Environment exampleEnv = new Environment(file, envConfig);
// Transaction txn = exampleEnv.beginTransaction(null,null); DatabaseConfig dbConfig = new DatabaseConfig(); dbConfig.setTransactional(true);
dbConfig.setAllowCreate(true);
dbConfig.setSortedDuplicates(false); Database myDB = exampleEnv.openDatabase(null, databaseDBName,
dbConfig);
// txn.commit();
// txn = exampleEnv.beginTransaction(null,null);
Cursor cursor = myDB.openCursor(null, null);
DatabaseEntry foundKey = new DatabaseEntry();
DatabaseEntry foundValue = new DatabaseEntry();
// cursor.getPrev()与cursor.getNext()的差别:一个是从前往后读取,一个是从后往前读取
// 这里讲訪问遍历数据库所有数据while循环噶为if推断,则就仅仅读取第一条数据
if (cursor.getNext(foundKey, foundValue, LockMode.DEFAULT) == OperationStatus.SUCCESS) {
theKey = new String(foundKey.getData(), "UTF-8");
}
cursor.close();
myDB.close();
exampleEnv.close();
} catch (Exception e) {
e.printStackTrace();
}
return theKey;
} // 读取已经爬取过的URL
public String readerUsedURL(String fileName, String databaseDBName,
String url) {
// 配置环境
EnvironmentConfig envConfig = new EnvironmentConfig();
// 设置配置事务
envConfig.setTransactional(true);
// 假设不存在就创建环境
envConfig.setAllowCreate(true);
File file = new File(fileName);
String theKey = null;
// file.mkdirs();
try {
Environment exampleEnv = new Environment(file, envConfig);
Transaction txn = exampleEnv.beginTransaction(null, null);
DatabaseConfig dbConfig = new DatabaseConfig();
dbConfig.setTransactional(true);
dbConfig.setAllowCreate(true);
dbConfig.setSortedDuplicates(false);
Database myDB = exampleEnv.openDatabase(txn, databaseDBName,
dbConfig);
txn.commit();
Cursor cursor = myDB.openCursor(null, null);
DatabaseEntry foundKey = new DatabaseEntry();
DatabaseEntry foundValue = new DatabaseEntry();
// cursor.getPrev()与cursor.getNext()的差别:一个是从前往后读取。一个是从后往前读取
// 这里讲訪问遍历数据库所有数据while循环噶为if推断。则就仅仅读取第一条数据
while (cursor.getNext(foundKey, foundValue, LockMode.DEFAULT) == OperationStatus.SUCCESS) {
theKey = new String(foundKey.getData(), "UTF-8");
if (theKey.equals(url)) {
return theKey;
}
}
cursor.close();
myDB.close();
exampleEnv.close();
} catch (Exception e) {
e.printStackTrace();
} return null;
} // 删除已经读取过的URL
public void deleteReadURL(String envHomePath, String databaseName,
String key) { Environment mydbEnv = null;
Database myDatabase = null;
// 创建一个EnvironmentConfig配置对象
EnvironmentConfig envCfg = new EnvironmentConfig();
// 假设设置了true则表示当数据库环境不存在时候又一次创建一个数据库环境,默觉得false.
envCfg.setAllowCreate(true);
// 设置数据库缓存大小
// envCfg.setCacheSize(1024 * 1024 * 20);
// 事务支持,假设为true。则表示当前环境支持事务处理,默觉得false,不支持事务处理。
envCfg.setTransactional(true);
try {
mydbEnv = new Environment(new File(envHomePath), envCfg);
DatabaseConfig dbCfg = new DatabaseConfig();
// 假设数据库不存在则创建一个
dbCfg.setAllowCreate(true);
// 假设设置为true,则支持事务处理,默认是false。不支持事务
dbCfg.setTransactional(true);
myDatabase = mydbEnv.openDatabase(null, databaseName, dbCfg);
DatabaseEntry keyEntry = new DatabaseEntry(key.getBytes("utf-8")); // 删除
myDatabase.delete(null, keyEntry);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != myDatabase) {
try {
myDatabase.close();
} catch (DatabaseException e) {
e.printStackTrace();
}
}
if (null != mydbEnv) {
// 在关闭环境前清理下日志
try {
mydbEnv.cleanLog();
} catch (DatabaseException e) {
e.printStackTrace();
}
try {
mydbEnv.close();
} catch (DatabaseException e) {
e.printStackTrace();
}
mydbEnv = null;
}
}
} public static void main(String[] args) {
OperatingDB odb = new OperatingDB();
// odb.writerURL( "c:/data/","www.163.com","data","123");
// odb.writerURL( "c:/data/","www.baidu.com","data","123");
String url = odb.readerURL("c:/data/", "data");
if(url != null){
odb.deleteReadURL("c:/data/","data",url);
}
else{
System.out.println("url is null !!!");
}
}
}

berkeley db储存URL队列的简单实现增、删、查的更多相关文章

  1. MyBatis简单的增删改查以及简单的分页查询实现

    MyBatis简单的增删改查以及简单的分页查询实现 <? xml version="1.0" encoding="UTF-8"? > <!DO ...

  2. MyBatis学习--简单的增删改查

    jdbc程序 在学习MyBatis的时候先简单了解下JDBC编程的方式,我们以一个简单的查询为例,使用JDBC编程,如下: Public static void main(String[] args) ...

  3. 通过JDBC进行简单的增删改查

    通过JDBC进行简单的增删改查(以MySQL为例) 目录 前言:什么是JDBC 一.准备工作(一):MySQL安装配置和基础学习 二.准备工作(二):下载数据库对应的jar包并导入 三.JDBC基本操 ...

  4. 初试KONCKOUT+WEBAPI简单实现增删改查

    初试KONCKOUT+WEBAPI简单实现增删改查 前言 konckout.js本人也是刚刚接触,也是初学,本文的目的是使用ko和asp.net mvc4 webapi来实现一个简单增删改查操作.Kn ...

  5. MVC3.0+knockout.js+Ajax 实现简单的增删改查

    MVC3.0+knockout.js+Ajax 实现简单的增删改查 自从到北京入职以来就再也没有接触MVC,很多都已经淡忘了,最近一直在看knockout.js 和webAPI,本来打算采用MVC+k ...

  6. SpringMVC之简单的增删改查示例(SSM整合)

    本篇文章主要介绍了SpringMVC之简单的增删改查示例(SSM整合),这个例子是基于SpringMVC+Spring+Mybatis实现的.有兴趣的可以了解一下. 虽然已经在做关于SpringMVC ...

  7. python3.6 使用 pymysql 连接 Mysql 数据库及 简单的增删改查操作

    1.通过 pip 安装 pymysql 进入 cmd  输入  pip install pymysql   回车等待安装完成: 安装完成后出现如图相关信息,表示安装成功. 2.测试连接 import ...

  8. python操作三大主流数据库(2)python操作mysql②python对mysql进行简单的增删改查

    python操作mysql②python对mysql进行简单的增删改查 1.设计mysql的数据库和表 id:新闻的唯一标示 title:新闻的标题 content:新闻的内容 created_at: ...

  9. 通过JDBC进行简单的增删改查(以MySQL为例) 目录

    通过JDBC进行简单的增删改查(以MySQL为例) 目录 前言:什么是JDBC 一.准备工作(一):MySQL安装配置和基础学习 二.准备工作(二):下载数据库对应的jar包并导入 三.JDBC基本操 ...

随机推荐

  1. map循环遍历

    data.map(function(item){ item.show = false; //将拿到的data循环给每一项添加show属性 });

  2. RegExp javascript正则表达式 :

    传统的查找字符串中的相关的字符 :<script type="text/javascript">var str='aaa23uihjkikh666jhjhk888kuh ...

  3. mysql忘记密码怎么处理

    1修改/etc/my.cnf文件 在[mysqld]下加一行skip-grant-tables 2.重启mysql使配置生效 3.免密码登录mysql并设置新密码 设置新的root密码,并刷新权限 4 ...

  4. 做一个可复用的 echarts-vue 组件(延迟动画加载)

    在 vue 项目使用 echarts 的场景中,以下三点不容忽视:1. 可视化的数据往往是异步加载的:2. 若一个页面存在大量的图表( 尤其当存在关系图和地图时 ),往往会导致该页面的渲染速度很慢并可 ...

  5. 网页里如何使用js禁用F12事件

    接上一篇,突然想起来,类似于网页里如何使用js禁用鼠标右击事件,还有禁用F12事件也可以禁用一下,总所周知,对于Web开发人员来说,常常要进行界面的调试.使用F12调试工具能够很方便地进行调试,查看h ...

  6. UI布局【转】

    转载自: https://www.cnblogs.com/wangdaijun/p/5519459.html https://www.jianshu.com/p/f781c40df57c Good U ...

  7. C语言变量名转字符串的方法

    C语言中将变量名转换成字符串使用的是#符号,来看下边两个宏定义: #define name2str(name) (#name) #define print_val(x) printf(#x" ...

  8. ie11 .pac代理脚本无法使用的问题

    参考: http://blogs.msdn.com/b/ieinternals/archive/2013/10/11/web-proxy-configuration-and-ie11-changes. ...

  9. 基于Core Text实现的TXT电子书阅读器

    本篇文章的项目地址基于Core Text实现的TXT电子书阅读器. 最近花了一点时间学习了iOS的底层文字处理的框架Core Text.在网上也参考很多资料,具体的资料在文章最后列了出来,有兴趣的可参 ...

  10. Qt之自定义布局管理器(QFlowLayout)

    简述 QFlowLayout,顾名思义-流布局,实现了处理不同窗口大小的布局.根据应用窗口的宽度来进行控件放置的变化. 具体实现要求不再赘述,请参考前两节内容. 简述 实现 效果 源码 实现 QFlo ...