Android數(shù)據(jù)庫框架:greenDAO vs LiteOrm

本文主要對(duì)比基于 Android SQLiteDatabase 引擎實(shí)現(xiàn)的數(shù)據(jù)庫框架:

greenDAO,官網(wǎng)鏈接 http://greenrobot.org/greendao 挫剑。

LiteOrm裸删,官網(wǎng)鏈接 http://litesuits.com

寫本文機(jī)緣起于微信群里有人談到Android數(shù)據(jù)庫框架,隨之一個(gè)有贊的朋友 @段揚(yáng)揚(yáng) 給了一份自己的測試數(shù)據(jù)贴铜,大概是這樣:

Android 數(shù)據(jù)庫框架性能測試

由這個(gè)圖可以看到 Realm(https://realm.io/cn) 基本上是性能最好的,它確實(shí)是一個(gè)牛逼的項(xiàng)目瀑晒,它不是基于 SQLite 而是基于一個(gè)自己的持久化引擎绍坝,具有 DB 文件跨平臺(tái)共享的優(yōu)點(diǎn),也存在一些不大不小的問題苔悦,點(diǎn)擊這里查看(若鏈接失效請(qǐng)google關(guān)鍵詞“為什么我不再使用Realm”)轩褐,綜合而言,還是可以一戰(zhàn)玖详,有興趣可以自己嘗試下把介。

里面沒有 LiteOrm(和 Ormlite 不是一回事)的測試數(shù)據(jù)勤讽,大概是知名度小,我就隨后要了一份他的測試代碼和原始數(shù)據(jù)(特別感謝這位同學(xué))拗踢,不過這份數(shù)據(jù)不全了地技,而且需要同一部測試機(jī),所以暫沒法做框架間全量對(duì)比了秒拔。

所以莫矗,本文主要針對(duì) greenDAO 和 LiteOrm,因?yàn)閾?jù)說 greenDAO 是基于Android SQLite的最快砂缩、性能最強(qiáng)悍的數(shù)據(jù)庫框架作谚,因?yàn)樗簧婕胺瓷洌康氖谴a輔助生成庵芭。

那么妹懒,我們從幾個(gè)簡單常見的角度和案例出發(fā)看看兩者的表現(xiàn)如何,將會(huì)涉及到:

  1. 性能表現(xiàn)情況
  2. 初步使用情況
  3. 應(yīng)對(duì)需求變化
  4. 待續(xù)...(精力有限双吆,等有機(jī)緣在弄噢)

一. LiteOrm 和 greenDAO 的性能表現(xiàn)

下面是一組直觀的測試數(shù)據(jù)眨唬,分為循環(huán)操作和批量操作兩種場景:

greenDAO vs LiteOrm 循環(huán)測試
greenDAO vs LiteOrm 批量測試

測試相關(guān)過程:

  1. 運(yùn)行 Test Demo,點(diǎn)擊 LiteOrm 測試按鈕好乐,通過日志觀察執(zhí)行完畢匾竿。

  2. 命令行卸載 Test Demo,重新運(yùn)行蔚万,點(diǎn)擊 GreenDAO 測試按鈕岭妖,通過日志觀察執(zhí)行完畢。

  3. 每次點(diǎn)擊按鈕反璃,所有操作會(huì)連續(xù)測試 10 次昵慌,取 10 次消耗時(shí)間的均值,安靜等待結(jié)果就好了淮蜈。

測試相關(guān)信息:

  1. 測試機(jī)為 Nexus5斋攀,取 10 次消耗時(shí)間的均值。

  2. 為了更直觀清晰的觀察數(shù)據(jù)梧田,將循環(huán)操作和批量操作分開統(tǒng)計(jì)淳蔼,否則因?yàn)閮烧邤?shù)據(jù)差異過大,柱狀圖無法看清小數(shù)據(jù)的數(shù)值柿扣。

  3. 循環(huán)單個(gè)操作比較耗時(shí)肖方,每次操作 1000 條數(shù)據(jù)。

  4. 批量操作因?yàn)檎w是事務(wù)的未状,效率非常高,每次操作 100000 條數(shù)據(jù)析桥。

測試相關(guān)結(jié)論:

  1. [循環(huán)插入]司草、[循環(huán)更新] 以及 [批量更新] 時(shí)艰垂,LiteOrm性能略強(qiáng)于greenDAO。

  2. [批量插入]埋虹、[查詢操作] 時(shí)猜憎,LiteOrm性能略遜于greenDAO。

  3. 除了 [批量查詢] 以外搔课,其他性能優(yōu)劣勢差距不明顯胰柑,[批量查詢]耗時(shí)差異主要來源于 LiteOrm 采用反射創(chuàng)建實(shí)例并賦值屬性,而 greenDAO 使用 new 操作直接創(chuàng)建對(duì)象并直接賦值屬性爬泥。

二. LiteOrm 和 greenDAO 的用法對(duì)比

我們以Note對(duì)象為例柬讨,展示操作過程,Note類如下:

public class Note {
  private Long id;
  private String text;
  private String comment;
  private java.util.Date date;

  public Note() {}

  public Note(Long id, String text, String comment, java.util.Date date) {
        this.id = id;
        this.text = text;
        this.comment = comment;
        this.date = date;
    }

  // getter and setter...
}

實(shí)例化它:

Note note = new Note(null, "title", "comment", new Date());
1. greenDAO 增改查刪

1.1 New Module:即新建一個(gè)子項(xiàng)目模塊袍啡,選擇 Java Libray踩官,它是一個(gè)java 項(xiàng)目,用來生成 greenDAO 所需要的輔助代碼境输。

1.2 寫DAO生成器:即子模塊里寫一個(gè) DAOGenerator 類生成 DAO蔗牡、Master、Session 等對(duì)象:

public class NoteDaoGenerator {

    public static void main(String[] args) throws Exception {
        Schema schema = new Schema(1, "lite.dbtest.greendao");

        addNote(schema);

        new DaoGenerator().generateAll(schema, "./app/src/main/java");
    }

    /** 指定 表名 和 列名嗅剖,以及主鍵 */
    private static void addNote(Schema schema) {
        Entity note = schema.addEntity("Note");     // 默認(rèn)表名為類名
        note.setTableName("CustomNote");            // 自定義表名
        note.addIdProperty().primaryKey().autoincrement(); //設(shè)置自增的主鍵
        note.addStringProperty("text").notNull(); // 非空字段
        note.addStringProperty("comment");
        note.addDateProperty("date");
    }
}

1.3 開始工作:實(shí)例化 DAO 對(duì)象后執(zhí)行各種操作:

 // 實(shí)例化 DAO
DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, "greendao-notes", null);
SQLiteDatabase db = helper.getWritableDatabase();
DaoMaster daoMaster = new DaoMaster(db);
DaoSession daoSession = daoMaster.newSession();
NoteDao noteDao = daoSession.getNoteDao();

// 執(zhí)行插入
noteDao.insert(note);
// 執(zhí)行更新
noteDao.update(note);
// 執(zhí)行查詢
noteDao.queryBuilder().where(NoteDao.Properties.Id.eq(1)).list();
// 執(zhí)行刪除
noteDao.delete(note);
2. LiteOrm 增改查刪

2.1 開始工作:實(shí)例化 LiteOrm 對(duì)象后執(zhí)行插入操作:

// 實(shí)例化 LiteOrm
LiteOrm liteOrm = LiteOrm.newSingleInstance(this, "liteorm-notes");

// 執(zhí)行插入
liteOrm.insert(note);
// 執(zhí)行更新
liteOrm.update(note);
// 執(zhí)行查詢
liteOrm.queryById(1, Note.class);
// 執(zhí)行刪除
liteOrm.delete(note);

2.2 不要沉迷辩越,沒有第二步,操作已經(jīng)完了信粮。区匣。。
簡單解釋下:上面例子默認(rèn)類名為表名蒋院,字段名為列名亏钩,id(或者_(dá)id)屬性為主鍵,但若要自定義 表名欺旧、列名 和 主鍵姑丑,需要給Model加注解:

// table name is "lite-note"
@Table("lite-note")
public class Note {

    @Column("_id")
    @PrimaryKey(AssignType.AUTO_INCREMENT)
    private Long id; // column name is "_id"

    @NotNull
    @Column("_text")
    private String text;// column name is "_text"

    private String comment;// column name is "comment"
    private java.util.Date date;// column name is "date"
}

二. LiteOrm 和 greenDAO 面對(duì)需求或模型更改

舉個(gè)簡單例子,Note對(duì)象增加了一系列新字段辞友,假設(shè)新增一個(gè)[title] 的屬性:

public class Note {
    private Long id;
    private String title; // 新增這個(gè) title 字段
    private String text;
    private String comment;
    private java.util.Date date;

    // 其他省略
}
greenDAO 面對(duì)需求or對(duì)象模型更改

第1步 自定義 SQLiteOpenHelper

greenDAO 常見得做法是在自定義你使用的 SQLiteOpenHelper栅哀,比如下面方案。

方案a : 刪舊表称龙,建新表留拾。

    /** WARNING: Drops all table on Upgrade! Use only during development. */
    public static class DevOpenHelper extends OpenHelper {
        public DevOpenHelper(Context context, String name, CursorFactory factory) {
            super(context, name, factory);
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            // 方案1,刪舊表鲫尊,建新表痴柔。
            dropAllTables(db, true);
            onCreate(db);
        }
    }

方案b :為舊表添加新列。

    /** WARNING: Drops all table on Upgrade! Use only during development. */
    public static class DevOpenHelper extends OpenHelper {
        public DevOpenHelper(Context context, String name, CursorFactory factory) {
            super(context, name, factory);
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            // 方案2疫向,為舊表添加新列咳蔚。
            db.execSQL("ALTER TABLE NOTE ADD COLUMN title");
        }
    }

如果不做上面操作豪嚎,那么升級(jí)后,是會(huì)發(fā)生下面這個(gè)異常谈火,因?yàn)橹敖ǖ谋聿淮嬖赱title]這個(gè)列呀侈询!

android.database.sqlite.SQLiteException: no such table: CustomNote (code 1): , while compiling: INSERT INTO "CustomNote" ("_id","TEXT","COMMENT","TITLE","DATE") VALUES (?,?,?,?,?)                                                         

第2步 修改 DAOGenerator 重新生成代碼

因?yàn)?greenDAO 操作的模型是由其代碼生成工具產(chǎn)生的,需要在 DAOGenerator 里添加一個(gè)字段糯耍,讓其重新生成一次模型扔字。

 Schema schema = new Schema(2, "lite.dbtest.greendao"); // 升級(jí)數(shù)據(jù)庫版本

Entity note = schema.addEntity("Note"); 
note.setTableName("CustomNote");
note.addIdProperty().primaryKey().autoincrement();
note.addStringProperty("title"); // 這里新增一個(gè)字段
note.addStringProperty("text").notNull();
note.addStringProperty("comment");
note.addDateProperty("date");

 new DaoGenerator().generateAll(schema, "./app/src/main/java");

運(yùn)行,greenDAO 通過 Schema 設(shè)置了數(shù)據(jù)庫版本温技,為我們生成了系列新的Note革为、Note DAO、Master荒揣、Session等類篷角。

至此,然后基本完成 [添加一個(gè)屬性字段] 的升級(jí)改造系任。

LiteOrm 面對(duì)需求or對(duì)象模型更改

好害怕恳蹲,會(huì)不會(huì)更麻煩。俩滥。嘉蕾。but。霜旧。错忱。
事實(shí)是 1 步也不需要走,什么都不用改挂据,因?yàn)槟P屠锩嫖覀円呀?jīng)新增了一個(gè)字段:

public class Note {
    private Long id;
    private String title; // 新增這個(gè) title 字段
    // ... 其他省略

這已經(jīng)足夠了以清,這受益于 LiteOrm 的自動(dòng)探測技術(shù),它會(huì)智能的判斷某個(gè)對(duì)象是不是發(fā)生了改變崎逃,從而同步到數(shù)據(jù)庫掷倔,這一切,開發(fā)者是無感知的个绍。

限于時(shí)間和個(gè)人精力問題勒葱,這篇分析并不全面,如果有誤還請(qǐng)不吝指正巴柿。不論哪款 ORM 或 數(shù)據(jù)庫框架凛虽,都各有利弊,至于該選用哪一款广恢,可自行斟酌凯旋,開發(fā)者最好自己親身體驗(yàn)下,畢竟絕知此事需躬行,只聽或者看別人的言論和結(jié)果瓦阐,無異于直接吃別人嚼過的東西蜗侈,沒有味道不重要篷牌,變了味會(huì)影響個(gè)人判斷睡蟋。

測試代碼已經(jīng)上傳Github:
https://github.com/litesuits/for-test/tree/master/DataBaseTest

最后,附一份<LiteOrm 和 系統(tǒng)原生SQLiteDatabase API 測試數(shù)據(jù)>


lite-vs-system.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末枷颊,一起剝皮案震驚了整個(gè)濱河市戳杀,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌夭苗,老刑警劉巖信卡,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異题造,居然都是意外死亡傍菇,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門界赔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來丢习,“玉大人,你說我怎么就攤上這事淮悼「赖停” “怎么了?”我有些...
    開封第一講書人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵袜腥,是天一觀的道長见擦。 經(jīng)常有香客問我,道長羹令,這世上最難降的妖魔是什么鲤屡? 我笑而不...
    開封第一講書人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮福侈,結(jié)果婚禮上酒来,老公的妹妹穿的比我還像新娘。我一直安慰自己癌刽,他們只是感情好役首,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著显拜,像睡著了一般衡奥。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上远荠,一...
    開封第一講書人閱讀 51,541評(píng)論 1 305
  • 那天矮固,我揣著相機(jī)與錄音,去河邊找鬼。 笑死档址,一個(gè)胖子當(dāng)著我的面吹牛盹兢,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播守伸,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼绎秒,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了尼摹?” 一聲冷哼從身側(cè)響起见芹,我...
    開封第一講書人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蠢涝,沒想到半個(gè)月后玄呛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡和二,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年徘铝,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片惯吕。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡惕它,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出混埠,到底是詐尸還是另有隱情怠缸,我是刑警寧澤,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布钳宪,位于F島的核電站揭北,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏吏颖。R本人自食惡果不足惜搔体,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望半醉。 院中可真熱鬧疚俱,春花似錦、人聲如沸缩多。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽衬吆。三九已至梁钾,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間逊抡,已是汗流浹背姆泻。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人拇勃。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓四苇,卻偏偏與公主長得像,于是被迫代替她去往敵國和親方咆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子月腋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容