有關(guān)DBFlow的Migration的幾個(gè)細(xì)節(jié)

個(gè)人原創(chuàng),轉(zhuǎn)載請注明出處:http://www.itdecent.cn/p/ff4fbbda2cd6

概述

DBFlow作為一款結(jié)合了簡易性與高效率的開源數(shù)據(jù)庫框架,深受不少android開發(fā)者的喜愛。我之前的一個(gè)app也采用了這款框架。最近app更新,需要升級數(shù)據(jù)庫。在不需要改變表的結(jié)構(gòu)的情況下,DBFlow的升級操作十分簡單,只需要改一下版本號就行了。可不巧我這次的更新偏偏有涉及到對表的結(jié)構(gòu)的修改,這樣一來就要用到DBFlow的Migration功能,查閱了一下官方文檔,發(fā)現(xiàn)有除了對數(shù)據(jù)本身的操作外,支持的修改數(shù)據(jù)庫結(jié)構(gòu)操作很有限(只支持對table的重命名和新增column),一些細(xì)節(jié)也講的不是很清楚,以下都是我個(gè)人的幾個(gè)實(shí)測(踩坑)。

Migration的觸發(fā)時(shí)機(jī)與執(zhí)行順序

DBFlow支持同時(shí)定義多個(gè)Migration,所有的Migration的觸發(fā)時(shí)機(jī)都是在第一次對數(shù)據(jù)庫進(jìn)行操作時(shí)觸發(fā)的(而不是Application或是MainActivity創(chuàng)建時(shí))。至于多個(gè)Migration的執(zhí)行順序,先上代碼:

@Database(version = 4)
public class AppDatabase {

    @Migration(version = 2, database = AppDatabase.class, priority = 0)
    public static class Migration1 extends BaseMigration {

        @Override
        public void migrate(DatabaseWrapper database) {
          // run some code here
          SQLite.update(Employee.class)
            .set(Employee_Table.status.eq("Invalid"))
            .where(Employee_Table.job.eq("Laid Off"))
            .execute(database); // required inside a migration to pass the wrapper
        }
    }
    @Migration(version = 4, database = AppDatabase.class, priority = 0)
    public static class Migration2 extends BaseMigration {

        @Override
        public void migrate(DatabaseWrapper database) {
          // run some code here
          ...
        }
    }
}
  1. 數(shù)據(jù)庫的版本會由低到高逐步升級,即假設(shè)之前的數(shù)據(jù)庫版本為1,要升級的版本為4,那么該段代碼會先執(zhí)行Migration1將版本升級到2,再執(zhí)行Migration2將版本升級到4。
  2. 只有@Migration里version高于原數(shù)據(jù)庫版本的Migration會執(zhí)行,即如果之前的版本為3,那么該段代碼只會執(zhí)行Migration2。
  3. 在version相同時(shí),由priority決定執(zhí)行順序,priority高的先執(zhí)行,如果version和priority都相同,則順序不確定(盡量避免),取決于哪個(gè)class先被找到。
  4. Migration只對已有的舊版本數(shù)據(jù)庫有效,新創(chuàng)建的數(shù)據(jù)庫不會執(zhí)行任何version > 0的Migration。

version = 0的Migration

DBFlow專門設(shè)計(jì)了version=0的Migration,用于數(shù)據(jù)庫的初始化。如果定義了這種Migration,則每次數(shù)據(jù)庫創(chuàng)建時(shí)都會自動調(diào)用該Migration,并且之后版本號為最新,不會在調(diào)用其他version的Migration。例如以下代碼:

@Database(version = 3)
public class AppDatabase {

    @Migration(version = 0, database = AppDatabase.class)
    public static class Migration0 extends BaseMigration {

        @Override
        public void migrate(DatabaseWrapper database) {
          // run some code here
          SQLite.update(Employee.class)
            .set(Employee_Table.status.eq("Invalid"))
            .where(Employee_Table.job.eq("Laid Off"))
            .execute(database); // required inside a migration to pass the wrapper
        }
    }
    @Migration(version = 3, database = AppDatabase.class)
    public static class Migration1 extends BaseMigration {

        @Override
        public void migrate(DatabaseWrapper database) {
          // run some code here
          ...
        }
    }
}

如果是第一次創(chuàng)建數(shù)據(jù)庫,那么只會執(zhí)行Migration0,反之如果之前有舊版數(shù)據(jù)庫(version一般大于0),那么只會執(zhí)行Migration1。

Migration里的Transaction

利用DBFlow的Transaction來進(jìn)行數(shù)據(jù)庫的批量操作非常簡單,尤其是速度最快的FastStoreModelTransaction,非常適合用來進(jìn)行數(shù)據(jù)庫創(chuàng)建和升級時(shí)的初始化錄入數(shù)據(jù)。如

FastStoreModelTransaction transaction = FastStoreModelTransaction
                    .saveBuilder(FlowManager.getModelAdapter(Knife.class))
                    .addAll(allKnives).build();
FlowManager.getDatabase(AppDatabase.class).executeTransaction(transaction);

不過,如果用version = 0的Migration來初始化就不能這么寫,會報(bào)錯(cuò),屬于循環(huán)調(diào)用數(shù)據(jù)庫。正確的寫法是:

@Database(version = 3)
public class AppDatabase {

    @Migration(version = 0, database = AppDatabase.class)
    public static class Migration0 extends BaseMigration {

        @Override
        public void migrate(DatabaseWrapper database) {
            FastStoreModelTransaction transaction = FastStoreModelTransaction
                    .insertBuilder(FlowManager.getModelAdapter(Knife.class))
                    .addAll(allKnives).build();
            transaction.execute(database);
        }
    }
}

對數(shù)據(jù)庫的其他結(jié)構(gòu)性操作

這就需要SQL的知識了,基本都是通過database.execSQL(SQLExpression)來進(jìn)行。比如刪除column,需要用execSQL先創(chuàng)建一張臨時(shí)表存原數(shù)據(jù),然后刪除原表,再新建一張與原表名稱相同的不包含要刪的column的新表,最后再將臨時(shí)表的數(shù)據(jù)錄入新表中。很麻煩是吧?這也是DBFlow目前為止不是很人性化的一點(diǎn)問題(相比之下Litepal在這點(diǎn)上就做的很好,雖然性能上略差一些)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容