berkeley db储存URL队列的简单实现增、删、查
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队列的简单实现增、删、查的更多相关文章
- MyBatis简单的增删改查以及简单的分页查询实现
MyBatis简单的增删改查以及简单的分页查询实现 <? xml version="1.0" encoding="UTF-8"? > <!DO ...
- MyBatis学习--简单的增删改查
jdbc程序 在学习MyBatis的时候先简单了解下JDBC编程的方式,我们以一个简单的查询为例,使用JDBC编程,如下: Public static void main(String[] args) ...
- 通过JDBC进行简单的增删改查
通过JDBC进行简单的增删改查(以MySQL为例) 目录 前言:什么是JDBC 一.准备工作(一):MySQL安装配置和基础学习 二.准备工作(二):下载数据库对应的jar包并导入 三.JDBC基本操 ...
- 初试KONCKOUT+WEBAPI简单实现增删改查
初试KONCKOUT+WEBAPI简单实现增删改查 前言 konckout.js本人也是刚刚接触,也是初学,本文的目的是使用ko和asp.net mvc4 webapi来实现一个简单增删改查操作.Kn ...
- MVC3.0+knockout.js+Ajax 实现简单的增删改查
MVC3.0+knockout.js+Ajax 实现简单的增删改查 自从到北京入职以来就再也没有接触MVC,很多都已经淡忘了,最近一直在看knockout.js 和webAPI,本来打算采用MVC+k ...
- SpringMVC之简单的增删改查示例(SSM整合)
本篇文章主要介绍了SpringMVC之简单的增删改查示例(SSM整合),这个例子是基于SpringMVC+Spring+Mybatis实现的.有兴趣的可以了解一下. 虽然已经在做关于SpringMVC ...
- python3.6 使用 pymysql 连接 Mysql 数据库及 简单的增删改查操作
1.通过 pip 安装 pymysql 进入 cmd 输入 pip install pymysql 回车等待安装完成: 安装完成后出现如图相关信息,表示安装成功. 2.测试连接 import ...
- python操作三大主流数据库(2)python操作mysql②python对mysql进行简单的增删改查
python操作mysql②python对mysql进行简单的增删改查 1.设计mysql的数据库和表 id:新闻的唯一标示 title:新闻的标题 content:新闻的内容 created_at: ...
- 通过JDBC进行简单的增删改查(以MySQL为例) 目录
通过JDBC进行简单的增删改查(以MySQL为例) 目录 前言:什么是JDBC 一.准备工作(一):MySQL安装配置和基础学习 二.准备工作(二):下载数据库对应的jar包并导入 三.JDBC基本操 ...
随机推荐
- 快速傅里叶变换(Fast-Fourier Transform,FFT)
数学定义: (详细参考:https://www.baidu.com/link?url=oYAuG2o-pia_U3DlF5n_MJZyE5YKfaVRUHTTDbM1FwM_kDTjGCxKpw_Pb ...
- vector ----- size函数注意事项
vector 的size函数返回vector大小,返回值类型为size_type,Member type size_type is an unsigned integral type,即无符号整数: ...
- 基本数据类型(int,bool,str)
1.int bit_lenth() 计算整数在内存中占用的二进制码的长度 十进制 二进制 长度(bit_lenth()) 1 1 1 2 10 2 4 100 3 8 1000 4 16 10000 ...
- [arc076e]connected?
题意: 给出一个$R\times C$的棋盘,其中$1$到$N$之间的每个正整数都会在棋盘上出现两次,第$i$个数出现的位置是$(X_{i,1},Y_{i,1})$和$(X_{i,2},Y_{i,2} ...
- DES 加密
package com.cloudunicomm.utils; import java.io.UnsupportedEncodingException; import java.security.Se ...
- win10 64位下VirtualBox安装CentOS6.9
第一步:安装VritualBox 百度“VritualBox”下载安装即可: 第二步:下载Linux镜像系统并安装 这里写出我参照的博客,很详细,我就不累赘了! 原文地址:http://blog.cs ...
- Eclipse集成Git插件及使用
目录(?)[+] 1 Git插件安装 11 下载插件 2 Git提交代码 21 建git的本地仓库 第一种 第二种 项目创建本地仓库后 如图 22 提交本地仓库 23 提交远程仓库 3 Git下载代码 ...
- HDU 1026 Ignatius and the Princess I(BFS+记录路径)
Ignatius and the Princess I Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (J ...
- 关于DPM(Deformable Part Model)算法中模型可视化的解释
搭建了自己的博客平台,本文地址:http://masikkk.com/blog/DPM-model-visualization/ DPM源代码(voc-release)中的模型可视化做的还算相当炫酷的 ...
- 使用ShareSDK实现第三方授权登录、分享以及获取用户资料效果,项目中包含:源码+效果图+项目结构图
[Android应用开发详解]第01期:第三方授权认证(一)实现第三方授权登录.分享以及获取用户资料 由于公司项目的需要,要实现在项目中使用第三方授权登录以及分享文字和图片等这样的效果,几经波折, ...