berkeley db儲存URL隊列的簡單實現增、刪、查

來源:互聯網
上載者:User



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存到另外一個數組中,並刪除隊列中已經訪問過的URLpackage 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;}// 讀取沒有訪問過的URLpublic 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;}// 讀取已經爬取過的URLpublic 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;}// 刪除已經讀取過的URLpublic 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 !!!");}}}



相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.