db4o是一個純對象的數據庫,現支持java和.NET。07年的時候,db4objects宣佈db4o已可以順利運行於Android平臺,當時db4objects公司和db4o的愛好者積極推進db4o運行於Google Android平臺,以期待讓db4o成爲Android上的首選數據庫平臺,但令人遺憾的是google最後選擇了sqlite作爲作爲android平臺的數據庫。但是沒有關係,db4objects有相應的解決方案,db4o可以無縫的運行於Android。
相對於關係型數據庫,db4o還顯得很年輕。大家對關係型數據庫的理念根深蒂固,所以一時很難理解對象型數據庫的理論。現在的數據庫課程也都是以關係型數據庫爲示例,對象型數據庫都是作爲一個新興的數據庫一筆帶過。這也導致很多人缺乏對象型數據的理論知識。真的想用好db4o,對象型數據的理論知識是必不可少的。例如對象型數據是沒有主鍵這個概念的,這會讓大多數人難以適應。
db4o也發展了幾年了,到現在好多人還不知道,網上的資料比較少,也是比較老的版本。現在主流的android應用也都是使用sqlite數據庫,這肯定是有原因的。這倒不是性能上的問題。Db4o的速度不見得會比關係型數據庫慢。其最大的問題在於理解數據對象的關係和操作。db4o沒有看上去那麼簡單,說實在的,我現在好多東西還沒搞明白。比如:
class A { int id; String name; List<B> list; }
存儲這種結構的對象,我一直搞不明白A和B的關聯情況。對應一些大應用還是建議使用比較成熟的東西。Android平臺上大家倒是可以一試,我也分享下自己的學習成果。現在db4o最新是8.x。穩定版本是7.x。本人以7.x演示。要說的是android平臺需要的db4o的jar要1M多(8.x版的要1.4M左右,網上說的400k應該是很早的版本了,官網上找不到了)。db4o的官網下載地址http://community.versant.com/Downloads/db4o.aspx。對應android開發只需要核心jar包db4o-7.x-core-java5.jar。在下載的壓縮包裏還有一個db4o數據庫的視圖工具OME(ObjectManager Enterprise),這是一個eclipse插件,是一個離線的安裝包。
Db4o的操作流程很簡單:打開數據庫文件,通過DAO讀寫數據,最後關閉數據庫,支持事務和併發。
作爲對象型數據庫是不用寫sql的,這點很爽。
對於db4o的基本操作不再多說,可以參考文章最後的參考鏈接。我做了一些封裝,並使用泛型來減少Dao的創建。如果不使用本例的泛型的話,你需要對每個bean創建Dao,如UserDao、CacheDao。在關係型數據庫中我們通過主鍵來識別一條記錄,但是對象型數據庫中沒有記錄,只有對象。db4o通過序列化java對象並存入文件,它識別是這個還是那個對象用的不是主鍵,而是UUID,這個UUID只有當一個對象被存入數據庫中才會被分配到,未存入數據庫的對象是沒有UUID的,所以說我們並不能通過UUID來更新一條數據.那怎樣更新一條數據?我們只能是先將這個對象查出來,然後修改內容再存入,或者查詢到直接刪除,然後存入新對象.
Db.java
package com.sljm.lfa.store;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import com.db4o.Db4oEmbedded;
import com.db4o.ObjectContainer;
import com.db4o.ObjectSet;
import com.db4o.config.CommonConfiguration;
import com.db4o.config.EmbeddedConfiguration;
import com.db4o.query.Query;
/**
* @author SunnyCoffee
* @date 2013-9-7
* @version 1.0
* @desc DB配置和操作接口
*/
public class Db<T extends Serializable> {
private Class<T> clazz;
private String unique;
private static ObjectContainer db;
/**
* 這裏的unique是class裏作爲索引的屬性
*
* @param clazz
* @param unique
*/
public Db(Class<T> clazz, String unique) {
this.clazz = clazz;
this.unique = unique;
}
// 打開數據庫
private ObjectContainer getDb() {
if (db == null || db.ext().isClosed()) {
db = Db4oEmbedded.openFile(conf(), getDbPath());
}
return db;
}
private String getDbPath() {
return "/mnt/sdcard/lfa.db4o";// 數據庫文件的路徑
}
// 數據庫的參數配置. 數據庫配置並沒有存儲到文件,每次打開數據庫執行此方法進行配置
private EmbeddedConfiguration conf() {
EmbeddedConfiguration conf = Db4oEmbedded.newConfiguration();
CommonConfiguration common = conf.common();
if (unique != null) {
common.objectClass(clazz).objectField(unique).indexed(true);
}
common.objectClass(clazz).cascadeOnUpdate(true);
common.objectClass(clazz).cascadeOnActivate(true);
return conf;
}
/**
* 存儲對象
*
* @param obj
*/
public void store(T obj) {
if (obj == null) {
return;
}
getDb().store(obj);
}
public void store(List<T> list) {
if (list == null) {
return;
}
for (T t : list) {
getDb().store(t);
}
}
/**
* 刪除對象
*
* @param obj
*/
public void delete(T obj) {
if (obj == null) {
return;
}
getDb().delete(obj);
}
public void delete(List<T> list) {
if (list == null) {
return;
}
for (T t : list) {
getDb().delete(t);
}
}
/**
* 查詢所有的某一對象
*
* @return
*/
public List<T> queryAll() {
Query query = getDb().query();
query.constrain(clazz);
query.descend(unique).orderAscending();
ObjectSet<T> set = query.execute();
List<T> list = fromObjectSet(set);
return list;
}
/**
* 根據id查詢一個對象
*
* @param field
* 字段
* @param id
* 字段的值
* @return
*/
public T queryById(Object id) {
List<T> list = queryWhere(unique, id);
if (list.size() == 0) {
return null;
}
return list.get(0);
}
public List<T> queryWhere(String field, Object value) {
Query query = getDb().query();
query.constrain(clazz);
query.descend(field).constrain(value);
ObjectSet<T> set = query.execute();
List<T> list = fromObjectSet(set);
return list;
}
public void close() {
getDb().commit();
if (db != null) {
db.close();
db = null;
}
}
private List<T> fromObjectSet(ObjectSet<T> set) {
List<T> list = new ArrayList<T>();
while (set.hasNext()) {
list.add(set.next());
}
return list;
}
}
db4o有3種查詢方式,官方一直推薦NQ(Native Queries),也就是原生查詢.首先它是類型安全的,其次查詢支持本地語言。還有就是QBE(Query by Example)和SODA(Simple Object Database Access)。QBE沒有用過,似乎沒什麼特點。SODA的是最低層的查詢方式,速度快、靈活性高,不足之處就是非類型安全的。本例中因爲有排序操作,考慮效率和易用性上使用了SODA。
DbApiImpl.java
package com.sljm.lfa.store;
import java.util.List;
import com.sljm.lfa.bean.Cache;
/**
* @author SunnyCoffee
* @date 2013-10-22
* @version 1.0
* @desc 數據庫接口實現類,查詢使用SODA。 NQ查詢更安全,考慮到效率和簡單使用了SODA,
* 如此一來必須使用字符串來表示字段,如果javaBean變動這裏字段必須做調整
*/
public class DbApiImpl implements DbApi {
public Cache getCacheById(final String id) {
Db<Cache> db = new Db<Cache>(Cache.class, "id");
Cache cache = db.queryById(id);
db.close();
return cache;
}
public void updateCache(Cache cache) {
Db<Cache> db = new Db<Cache>(Cache.class, "id");
Cache c = db.queryById(cache.getId());
db.delete(c);
db.store(cache);
db.close();
}
public void clearCache() {
Db<Cache> db = new Db<Cache>(Cache.class, "id");
List<Cache> list = db.queryAll();
db.delete(list);
db.close();
}
}
這裏注意兩點一個是Serializable接口,一個是空構造方法。
Cache.java
package com.sljm.lfa.bean;
import java.io.Serializable;
/**
* @author SunnyCoffee
* @create 2013-8-21
* @version 1.0
* @desc 緩存bean
*/
public class Cache implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private String id;
private long lastModified;
private long valid;
private Object result;
public Cache() {
}
// set and get
}
參考鏈接: