對象數據庫(ODBMS) db4o試用(Java version)
我覺得我現在中了兩種毒:Java和SQL。西諺有云:When you have a hammer, everything looks like a nail。只要動手寫程序,頭腦中不自覺地就public class...其實很多時候一兩行簡短的scripts就可以了,即使像在Windows上,我們也可以寫jscript、wsh腳本。而在資料儲存 上,關系數據庫更是不二法寶。拿到一個項目,我馬上就要將它分解成各個Table,我覺得SQL是如此強大和靈活,以至于一見到O/R映射就覺得厭惡,直 到現在我也沒有碰過Hibernate。呵呵,抱怨了半天,與其在O/R映射中苦苦掙扎,不如跳出來看看其它的風景,比如:ODBMS(對象數據庫)。學士剛下載了db4o這個所謂對象數據庫,試著玩了一下,雖尚不知味之甘苦,勉得以一窺豹斑。
db4o 目前是Version 5.0,僅需要一個jar文件,我用的支持JDK5的那個:db4o-5.0-java5.jar; 你如果用的其它版本的JDK,有相對應的jar文件。這個jar文件就是數據庫,可不要想象成JDBC Driver之類的東東,JDBC Driver是RDBMS(關系數據庫)才需要的東東,呵呵。
好了,閑話不說,我們現在試試這個ODBMS。首先,建一個你想要保存的對象,我寫了一個非常簡單的Student.java:
public class Student {
private String name;
private int points;
/** Creates a new instance of Student */
public Student(String name, int points) {
this.name = name;
this.points = points;
}
public String getName() {
return name;
}
public int getPoints() {
return points;
}
public void addPoints(int points) {
this.points += points;
}
public String toString() {
return name + "/" + points;
}
}
這個類非常簡單,只有兩個instance fields,學生姓名和分數,以及一些簡單的methods,完全沒有用任何跟db4o相關的代碼。然后我們就可以將Student的實例放入數據庫操作了:InsertObj2Db4o.java:
import java.io.File;
import java.util.List;
import com.db4o.Db4o;
import com.db4o.ObjectContainer;
import com.db4o.ObjectSet;
import com.db4o.query.*;
/**
*
* @author Stevech
*/
public class InsertObj2Db4o {
/** Creates a new instance of InsertObj2Db4o */
public InsertObj2Db4o() {
}
public static void main(String[] args) {
ObjectContainer db = Db4o.openFile("student.yap");
try {
storeStudents(db);
retrieveAllStudents(db);
retrieveStudentByName(db);
retrieveStudentByPoints(db);
updateStudent(db);
deleteStudent(db);
descendStudents(db);
retrievePartStudents(db);
} finally {
db.close();
}
}
public static void storeStudents(ObjectContainer db) {
Student bg = new Student("Bill Gates", 119);
Student sm = new Student("Scott McNealy", 102);
Student sj = new Student("Steve Jobs", 150);
Student rs = new Student("Richard Stallman", 500);
Student le = new Student("Larry Elison", 105);
Student sc = new Student("Steve Cheng", 95);
db.set(bg);
db.set(sm);
db.set(sj);
db.set(rs);
db.set(le);
db.set(sc);
System.out.println("Added " + bg + ", " + sm + ", " + sj);
System.out.println("Added " + rs + ", " + le + ", " + sc);
}
public static void retrieveAllStudents(ObjectContainer db) {
ObjectSet<Student> result = db.get(Student.class);
listResult(result);
}
public static void retrieveStudentByName(ObjectContainer db) {
Student proto = new Student("Bill Gates", 0); // Note: 0 is default value for int
ObjectSet<Student> result = db.get(proto);
listResult(result);
}
public static void retrieveStudentByPoints(ObjectContainer db) {
Student proto = new Student(null, 500);
ObjectSet<Student> result = db.get(proto);
listResult(result);
}
public static void updateStudent(ObjectContainer db) {
ObjectSet<Student> result = db.get(new Student("Steve Cheng", 95));
Student found = result.next();
found.addPoints(10);
db.set(found);
retrieveAllStudents(db);
System.out.println("Added 10 points for " + found);
}
public static void deleteStudent(ObjectContainer db) {
ObjectSet<Student> result = db.get(new Student("Steve Cheng", 0));
Student found = result.next();
db.delete(found);
retrieveAllStudents(db);
System.out.println("Deleted " + found);
}
public static void descendStudents(ObjectContainer db) {
Query query = db.query();
query.constrain(Student.class);
Query descendQuery = query.descend("points").orderDescending();
ObjectSet<Student> result = query.execute();
listResult(result);
}
public static void retrievePartStudents(ObjectContainer db) {
List<Student> result = db.query(new Predicate<Student>() {
public boolean match(Student s) {
return s.getPoints() > 120 && s.getPoints() < 500 || s.getName().equals("Bill Gates");
}
});
listResult(result);
}
public static void listResult(ObjectSet result) {
//System.out.println(result.size());
System.out.println("************************************");
while(result.hasNext()) {
System.out.println(result.next());
}
}
public static void listResult(java.util.List result){
//System.out.println(result.size());
System.out.println("************************************");
for(int x = 0; x < result.size(); x++)
System.out.println(result.get(x));
}
}
我們一點一點地看:
首 先,與RDBMS一樣,我們需要連接到數據庫。db4o可以運行為C/S模式(或者叫Remote模式,就像Oracle, PostgreSQL, MSSQLSERVER, etc),也可以是local模式(或者叫embed模式)。Borland的JDataStore也與此相似,不同的是JDataStore是 RDBMS。我們這里用local模式:
ObjectContainer db = Db4o.openFile("student.yap");
它打開當前目錄下的student.yap文件(也即數據庫文件),如果沒有,就自動新建一個。然后,就該往里面添數據了:(storeStudents method)
Student bg = new Student("Bill Gates", 119);
...
db.set(bg);
非常地簡單。
同樣,取出數據也是一樣地簡單:(retrieveAllStudents method)
ObjectSet<Student> result = db.get(Student.class);
先告訴db(一個ObjectContainer實例)我們要取出數據的類型是Student,然后所有的Student類型的數據就存在ObjectSet中了。
現實中,絕大多數時候我們只對那些滿足特定條件的數據感興趣,比如說,我們對Bill Gates同學有極大的興趣:(retrieveStudentByName method)
Student proto = new Student("Bill Gates", 0); // Note: 0 is default value for int
ObjectSet<Student> result = db.get(proto);
我 們先建立一個Student的模板,name為Bill Gates,而points為任意值。然后將這個模板遞給db即可。值得注意的是這里points值為0,這并不是我們希望Bill Gates同學的分數為鴨蛋,而僅僅因為0是int的默認值,如果這個參數是Object類型,我們這里就會賦予它默認值null(參見 retrieveStudentByPoints method)當指定的參數為默認值時,意味著我們不對它進行任何限制。這給做模板的方法在db4o中稱作QBE (Query by Example),由于顯而易見的缺點,實際上往往我們使用的是另一種稱作Native Queries的方法來選取數據(見后面retrievePartStudents method)
現在,我們覺得Steve Cheng同學太可憐了,因為只有他的分數在100以下,因此我們決定給他加上10分(上帝保佑你碰到這樣的教師):(updateStudent method)
ObjectSet<Student> result = db.get(new Student("Steve Cheng", 95));
Student found = result.next();
found.addPoints(10);
db.set(found);
我 們先將Steve Cheng從數據庫中取出來放在一個名為found的Student對象中,然后調用Student的instance method: addPoints(int points)來給found加上10分。然后,將found重新放入db中。這就完成了更新操作。
我 們再來看看這個班級里的學生。“Oh, my God!” 有人合不上嘴了,“這個班里全是大腕兒級的人物!But wait, 這個叫Steve Cheng的是什么東西啊?竟然跟Bill Gates (RMS,如果說話的人是GNU fellow的話)列在一起。強烈要求廢了他!!”顧客就是上帝,我們只得對不起Steve Cheng了,將他從數據庫中刪除:(deleteStudent method)
ObjectSet<Student> result = db.get(new Student("Steve Cheng", 0));
Student found = result.next();
db.delete(found);
與更新類似,我們先得選出Steve Cheng放到found對象中,然后,db.delete(found),Steve Cheng就從這個子虛烏有的班級中消失了。
好了,剩下的都是英雄好漢,我們按他們各自的分數來給他們排座次(這至少比梁山好漢搞天降蝌蚪文排座次公平):(descendStudents method)
Query query = db.query();
query.constrain(Student.class);
Query descendQuery = query.descend("points").orderDescending();
ObjectSet<Student> result = query.execute();
這里的做法不同于QBE或是Native Queriy,叫做SODA Query,是屬于比較底層的方法,但還是很容易看明白的。雖然沒有Native Queriy那么易于使用,但功能卻是很強大的。因此在實際中一些地方還是需要用到SODA Query的。
排 了座次,我們要從精英之中選幸運兒去參加由HAL公司贊助的夏令營活動了,只有那些成績介于120到500之間的才能獲得這個天上掉的餡兒餅,(< 500,這不是明顯排斥RMS嘛),不過只要你是Bill Gates則不管你成績如何你都能撿這個餡兒餅吃(??):(retrievePartStudents method)
List<Student> result = db.query(new Predicate<Student>() {
public boolean match(Student s) {
return s.getPoints() > 120 && s.getPoints() < 500 || s.getName().equals("Bill Gates");
}
});
這是一個典型的Native Query(這可是db4o大書特書引以為傲的東東),Predicate是定義在import com.db4o.query.*里的一個抽象類:
public abstract class Predicate<ExtentType>extends java.lang.Objectimplements java.io.Serializable
定 義了public abstract boolean match(ExtentType candidate)方法。如果這個方法返回true,則candidate被放入result中。而條件語句也是標準的Java語句(如果使用.Net 則是標準的.Net語句)(而不是像RDBMS的SQL),這也是db4o自豪的地方。
更多有關db4o的消息,請訪問http://www.db4o.com
posted on 2006-01-04 22:10 西門町學士 閱讀(338) 評論(0) 編輯 收藏 所屬分類: Java