在使用Berkeley DB c++ Edition的時候發現有些接口不是太了解,發現網上好多都是Java版本的資訊,對付發現他們的命名基本相同。是以轉載一下以便以後查找。
一、 簡介
Berkeley DB Java Edition (JE)是一個完全用JAVA寫的,它适合于管理海量的,簡單的資料。
l 能夠高效率的處理1到1百萬條記錄,制約JE資料庫的往往是硬體系統,而不是JE本身。
l 多線程支援,JE使用逾時的方式來處理線程間的死瑣問題。
l Database都采用簡單的key/value對應的形式。
l 事務支援。
l 允許建立二級庫。這樣我們就可以友善的使用一級key,二級key來通路我們的資料。
l 支援RAM緩沖,這樣就能減少頻繁的IO操作。
l 支援日志。
l 資料備份和恢複。
l 遊标支援。
二、 擷取JE
JE下載下傳位址:
http://www.oracle.com/technology/software/products/berkeley-db/je/index.html
解開包後 把JE_HOME/lib/je-<version>.jar 中的jar檔案添加到你的環境變量中就可以使用je了。
相關幫助文檔可以參考 JE_HOME/docs/index.html
源代碼見JE_HOME/src/*.*
三、 JE常見的異常
DatabaseNotFoundException 當沒有找到指定的資料庫的時候會傳回這個異常
DeadlockException 線程間死鎖異常
RunRecoveryException 回收異常,當發生此異常的時候,你必須得重新打開環境變量。
四、 關于日志檔案必須了解的六項
JE的日志檔案跟其他的資料庫的日志檔案不太一樣,跟C版的DBD也是有差別的
l JE的日志檔案隻能APPEND,第一個日志檔案名是 00000000.jdb,當他增長到一定大小的時候(預設是10M),開始寫第二個日志檔案00000001.jdb,已此類推。
l 跟C版本有所不同,JE的資料日志和事務日志是放在一起的,而不是分開放的。
l JE cleaner負責清掃沒用到的磁盤空間,删除後,或者更新後新的記錄會追加進來,而原有的記錄空間就不在使用了,cleaner負責清理不用的空間。
l 清理并不是立即進行的,當你關閉你的資料庫環境後,通過調用一個cleaner方法來清理。
l 清理也不是隻動執行的,需要你自己手動調用cleaner 方法來定時清理的。
l 日志檔案的删除僅發生在檢查點之後。cleaner準備出哪些log 檔案需要被删除,當檢查點過後,删掉一些不在被使用的檔案。每寫20M的日志檔案就執行一次檢查點,預設下。
五、 建立資料庫環境
JE要求在任何DATABASE操作前,要先打開資料庫環境,就像我們要使用資料庫的話必須得先建立連接配接一樣。你可以通過資料庫環境來建立和打開database,或者更改database名稱和删除database.
可以通過Environments對象來打開環境,打開環境的時候設定的目錄必須是已經存在的目錄,否則會出錯誤。預設情況下,如果指定的database不存在則不會自動建立一個新的detabase,但可以通過設定setAllowCreate來改變這一情況。
1. 打開database環境
示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 | package je.gettingStarted;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.Environment;
import com.sleepycat.je.EnvironmentConfig;
import java.io.File;
...
Environment myDbEnvironment = null;
try {
EnvironmentConfig envConfig = new EnvironmentConfig();
envConfig.setAllowCreate(true);//如果不存在則建立一個
myDbEnvironment = new Environment(new File("/export/dbEnv"), envConfig);
} catch (DatabaseException dbe) {
// 錯誤處理
} |
2. 關閉database環境
可以通過Environment.close()這個方法來關閉database環境,當你完成資料庫操作後一定要關閉資料庫環境。
示例:
1
2
3
4
5
6
7
8
9
10
11
12 | import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.Environment;
...
try {
if (myDbEnvironment != null) {
myDbEnvironment.close();
}
} catch (DatabaseException dbe) {
// Exception handling goes here
} |
3. 清理日志
通常在關閉資料庫連接配接的時候,有必要清理下日志,用以釋放更多的磁盤空間。我們可以在Environment.close前執行下Environment.cleanLog()來達到此目的。
示例:
1
2
3
4
5
6
7
8
9
10
11
12
13 | import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.Environment;
...
try {
if (myDbEnvironment != null) {
myDbEnvironment.cleanLog(); // 在關閉環境前清理下日志
myDbEnvironment.close();
}
} catch (DatabaseException dbe) {
// Exception handling goes here
} |
4. Database環境的配置
可以通過EnvironmentConfig這個對象來配置database環境。如果想得到目前環境的配置資訊則可以通過Environment.getConfig()方法得到目前環境的配置資訊。
也可以使用EnvironmentMutableConfig來配置環境,其實 EnvironmentConfig是EnvironmentMutableConfig的子類,是以EnvironmentMutableConfig能夠使用的設定,EnvironmentConfig也同樣能夠使用。
如果你要擷取目前環境的使用情況,那麼你可以通過使用EnvironmentStats.getNCacheMiss().來監視RAM cache命中率。EnvironmentStats可以由Environment.getStats()方法擷取。
EnvironmentConfig常見方法介紹
l EnvironmentConfig.setAllowCreate() ;
如果設定了true則表示當資料庫環境不存在時候重新建立一個資料庫環境,預設為false.
l EnvironmentConfig.setReadOnly()
以隻讀方式打開,預設為false.
l EnvironmentConfig.setTransactional()
事務支援,如果為true,則表示目前環境支援事務處理,預設為false,不支援事務處理。
EnvironmentMutableConfig的介紹
l setCachePercent()
設定目前環境能夠使用的RAM占整個JVM記憶體的百分比。
l setCacheSize()
設定目前環境能夠使用的最大RAM。機關BYTE
l setTxnNoSync()
當送出事務的時候是否把緩存中的内容同步到磁盤中去。
true 表示不同步,也就是說不寫磁盤
l setTxnWriteNoSync()
當送出事務的時候,是否把緩沖的log寫到磁盤上
true 表示不同步,也就是說不寫磁盤
示例一:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 | package je.gettingStarted;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.Environment;
import com.sleepycat.je.EnvironmentConfig;
import java.io.File;
...
Environment myDatabaseEnvironment = null;
try {
EnvironmentConfig envConfig = new EnvironmentConfig();
//當環境不存在的時候自動建立環境
envConfig.setAllowCreate(true);
//設定支援事務
envConfig.setTransactional(true);
myDatabaseEnvironment =
new Environment(new File("/export/dbEnv"), envConfig);
} catch (DatabaseException dbe) {
System.err.println(dbe.toString());
System.exit(1);
} |
示例二:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | package je.gettingStarted;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.Environment;
import com.sleepycat.je.EnvironmentMutableConfig;
import java.io.File;
...
try {
Environment myEnv = new Environment(new File("/export/dbEnv"), null);
EnvironmentMutableConfig envMutableConfig =
new EnvironmentMutableConfig();
envMutableConfig.setTxnNoSync(true);
myEnv.setMutableConfig(envMutableConfig);
} catch (DatabaseException dbe) {
// Exception handling goes here
} |
示例三:
1
2
3
4
5 | import com.sleepycat.je.Environment;
...
//沒有命中的CACHE
long cacheMisses = myEnv.getStats(null).getNCacheMiss();
... |
5. Database操作
在BDB中,資料是以key/value方式成隊出現的。
打開database
可以通過environment.openDatabase()方法打開一個database,在調用這個方法的時候必須指定database的名稱。和databaseConfig() (注:資料庫設定)
示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 | package je.gettingStarted;
import com.sleepycat.je.Database;
import com.sleepycat.je.DatabaseConfig;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.Environment;
import com.sleepycat.je.EnvironmentConfig;
import java.io.File;
...
Environment myDbEnvironment = null;
Database myDatabase = null;
...
try {
// 打開一個環境,如果不存在則建立一個
EnvironmentConfig envConfig = new EnvironmentConfig();
envConfig.setAllowCreate(true);
myDbEnvironment = new Environment(new File("/export/dbEnv"), envConfig);
// 打開一個資料庫,如果資料庫不存在則建立一個
DatabaseConfig dbConfig = new DatabaseConfig();
dbConfig.setAllowCreate(true);
myDatabase = myDbEnvironment.openDatabase(null,
"sampleDatabase", dbConfig); //打開一個資料庫,資料庫名為
//sampleDatabase,資料庫的配置為dbConfig
} catch (DatabaseException dbe) {
// 錯誤處理
} |
關閉database
通過調用Database.close()方法來關閉資料庫,但要注意,在關閉資料庫前必須得先把遊标先關閉。
使用示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14 | import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.Database;
import com.sleepycat.je.Environment;
...
try {
if (myDatabase != null) {
myDatabase.close();
}
if (myDbEnvironment != null) {
myDbEnvironment.close();
}
} catch (DatabaseException dbe) {
// 錯誤處理
} |
設定資料庫屬性
其實設定資料庫屬性跟設定環境屬性差不多,JE中通過DatabaseConfig對象來設定資料庫屬性。你能夠設定的資料庫屬性如下。
l DatabaseConfig.setAllowCreate()
如果是true的話,則當不存在此資料庫的時候建立一個。
l DatabaseConfig.setBtreeComparator()
設定用于Btree比較的比較器,通常是用來排序
l DatabaseConfig.setDuplicateComparator()
設定用來比較一個key有兩個不同值的時候的大小比較器。
l DatabaseConfig.setSortedDuplicates()
設定一個key是否允許存儲多個值,true代表允許,預設false.
l DatabaseConfig.setExclusiveCreate()
以獨占的方式打開,也就是說同一個時間隻能有一執行個體打開這個database。
l DatabaseConfig.setReadOnly()
以隻讀方式打開database,預設是false.
l DatabaseConfig.setTransactional()
如果設定為true,則支援事務處理,預設是false,不支援事務。
使用示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 | package je.gettingStarted;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.Database;
import com.sleepycat.je.DatabaseConfig;
...
// Environment open omitted for brevity
...
Database myDatabase = null;
try {
DatabaseConfig dbConfig = new DatabaseConfig();
dbConfig.setAllowCreate(true);
dbConfig.setSortedDuplicates(true);
myDatabase =
myDbEnv.openDatabase(null,
"sampleDatabase",
dbConfig);
} catch (DatabaseException dbe) {
// Exception handling goes here.
} |
一些用來管理的方法
l Database.getDatabaseName()
取得資料庫的名稱
如:String dbName = myDatabase.getDatabaseName();
l Database.getEnvironment()
取得包含這個database的環境資訊
如:Environment theEnv = myDatabase.getEnvironment();
l Database.preload()
預先加載指定bytes的資料到RAM中。
如:myDatabase.preload(1048576l); // 1024*1024
l Environment.getDatabaseNames()
傳回目前環境下的資料庫清單
如:
1
2
3
4
5 | import java.util.List;
List myDbNames = myDbEnv.getDatabaseNames();
for(int i=0; i < myDbNames.size(); i++) {
System.out.println("Database Name: " + (String)myDbNames.get(i));
} |
l Environment.removeDatabase()
删除目前環境中指定的資料庫。
如:
1
2
3 | String dbName = myDatabase.getDatabaseName();
myDatabase.close();
myDbEnv.removeDatabase(null, dbName); |
l Environment.renameDatabase()
給目前環境下的資料庫改名
如:
1
2
3
4 | String oldName = myDatabase.getDatabaseName();
String newName = new String(oldName + ".new", "UTF-8");
myDatabase.close();
myDbEnv.renameDatabase(null, oldName, newName); |
l Environment.truncateDatabase()
清空database内的所有資料,傳回清空了多少條記錄。
如:
1
2
3 | Int numDiscarded= myEnv.truncate(null,
myDatabase.getDatabaseName(),true);
System.out.println("一共删除了 " + numDiscarded +" 條記錄 從資料庫 " + myDatabase.getDatabaseName()); |
6. Database 記錄
JE的記錄包含兩部分,key鍵值和value資料值,這兩個值都是通過DatabaseEntry對象封裝起來,是以說如果要使用記錄,則你必須建立兩個DatabaseEntry對象,一個是用來做為key,另外一個是做為value.
DatabaseEntry能夠支援任何的能夠轉換為bytes數組形式的基本資料。包括所有的JAVA基本類型和可序列化的對象.
使用記錄
示例一:把字元串轉換DatabaseEntry
1
2
3
4
5
6
7
8
9
10
11
12 | package je.gettingStarted;
import com.sleepycat.je.DatabaseEntry;
...
String aKey = "key";
String aData = "data";
try {
//設定key/value,注意DatabaseEntry内使用的是bytes數組
DatabaseEntry theKey=new DatabaseEntry(aKey.getBytes("UTF-8"));
DatabaseEntry theData=new DatabaseEntry(aData.getBytes("UTF-8"));
} catch (Exception e) {
// 錯誤處理
} |
示例二:把DatabaseEntry裡的資料轉換成字元串
1
2
3
4 | byte[] myKey = theKey.getData();
byte[] myData = theData.getData();
String key = new String(myKey, "UTF-8");
String data = new String(myData, "UTF-8"); |
讀和寫database 記錄
讀和寫database記錄的時候大體是基本一樣的,唯一有差別的是每個key寫是否允許寫多條記錄,預設情況下是不支援多條記錄的。
a) 你可以使用如下方法向database 裡添加記錄
l Database.put()
向database中添加一條記錄。如果你的database不支援一個key對應多個data或目前database中已經存在該key了,則使用此方法将使用新的值覆寫舊的值。
l Database.putNoOverwrite()
向database中添加新值但如果原先已經有了該key,則不覆寫。不管database是否允許支援多重記錄(一個key對應多個value),隻要存在該key就不允許添加,并且傳回perationStatus.KEYEXIST資訊。
l Database.putNoDupData()
想database中添加一條記錄,如果database中已經存在了相同的 key和value則傳回 OperationStatus.KEYEXIST.
使用示例:
1
2
3
4
5
6
7
8
9
10
11
12
13 | package je.gettingStarted;
import com.sleepycat.je.Database;
import com.sleepycat.je.DatabaseEntry;
...
String aKey = "myFirstKey";
String aData = "myFirstData";
try {
DatabaseEntry theKey = new DatabaseEntry(aKey.getBytes("UTF-8"));
DatabaseEntry theData = new DatabaseEntry(aData.getBytes("UTF-8"));
myDatabase.put(null, theKey, theData);
} catch (Exception e) {
// Exception handling goes here
} |
b) 你可以使用如下方法從database 裡讀取記錄
1. Database.get()
基本的讀記錄的方法,通過key的方式來比對,如果沒有改記錄則傳回OperationStatus.NOTFOUND。
l Database.getSearchBoth()
通過key和value來同時比對,同樣如果沒有記錄比對key和value則會傳回OperationStatus.NOTFOUND。
使用示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 | package je.gettingStarted;
import com.sleepycat.je.Database;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.LockMode;
import com.sleepycat.je.OperationStatus;
...
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
} |
c) 删除記錄
可以使用Database.delete()這個方法來删除記錄。如果你的database支援多重記錄,則目前key下的所有記錄都會被删除,如果隻想删除多重記錄中的一條則可以使用遊标來删除。
當然你也可以使用Environment.truncateDatabase()這個方法來清空database 中的所有記錄。
使用示例:
1
2
3
4
5
6
7
8
9
10 | package je.gettingStarted;
import com.sleepycat.je.Database;
import com.sleepycat.je.DatabaseEntry;
...
try {
String aKey = "myFirstKey";
DatabaseEntry theKey = new DatabaseEntry(aKey.getBytes("UTF-8"));
myDatabase.delete(null, theKey);
} catch (Exception e) {
} |
d) 送出事務
當你對database進行了寫操作的時候,你的修改不一定馬上就能生效,有的時候他僅僅是緩存在RAM中,如果想讓你的修改立即生效,則可以使用Environment.sync()方法來把資料同步到磁盤中去。
e) 不同類型的資料的處理
1. 你可以使用DatabaseEntry來綁定基本的JAVA資料類型,主要有String、Character、Boolean、Byte、Short、Integer、Long、Float、Double.
使用示例一:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 | package je.gettingStarted;
import com.sleepycat.bind.EntryBinding;
import com.sleepycat.bind.tuple.TupleBinding;
import com.sleepycat.je.DatabaseEntry;
...
try {
String aKey = "myLong";
DatabaseEntry theKey = new
DatabaseEntry(aKey.getBytes("UTF-8"));
Long myLong = new Long(123456789l);
DatabaseEntry theData = new DatabaseEntry();
EntryBinding myBinding =
TupleBinding.getPrimitiveBinding(Long.class);
myBinding.objectToEntry(myLong, theData);
myDatabase.put(null, theKey, theData);
} catch (Exception e) {
// Exception handling goes here
} |
使用示例二:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 | package je.gettingStarted;
import com.sleepycat.bind.EntryBinding;
import com.sleepycat.bind.tuple.TupleBinding;
import com.sleepycat.je.Database;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.LockMode;
import com.sleepycat.je.OperationStatus;
...
Database myDatabase = null;
try {
String aKey = "myLong";
DatabaseEntry theKey = new
DatabaseEntry(aKey.getBytes("UTF-8"));
DatabaseEntry theData = new DatabaseEntry();
EntryBinding myBinding =
TupleBinding.getPrimitiveBinding(Long.class);
OperationStatus retVal = myDatabase.get(null, theKey, theData,
LockMode.DEFAULT);
String retKey = null;
if (retVal == OperationStatus.SUCCESS) {
Long theLong = (Long) myBinding.entryToObject(theData);
retKey = new String(theKey.getData(), "UTF-8");
System.out.println("For key: '" + retKey + "' found Long: '" +
theLong + "'.");
} else {
System.out.println("No record found for key '" + retKey + "'.");
}
} catch (Exception e) {
// Exception handling goes here
} |
From:http://cllovelf.blog.chinajavaworld.com/entry/282