zoukankan      html  css  js  c++  java
  • 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




    一些特性:

    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 !!!");
    		}
    	}
    }
    



  • 相关阅读:
    nightwatchjs --Expect element to not include text
    Iterating elements using NightWatchJS
    nightwatch 切换窗口
    nodejs读取配置文件
    spring 事务
    重载,重写,重构
    python 元组不变 列表可变
    WebStorm ES6 语法支持设置
    docker日志
    curl -O 下载文件
  • 原文地址:https://www.cnblogs.com/yfceshi/p/6993159.html
Copyright © 2011-2022 走看看