android平臺db4o使用示例

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
}


參考鏈接:

http://www.ibm.com/developerworks/cn/java/j-db4o/

http://www.db4o.com

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章