預先填入 Room 資料庫

有時,您可能希望讓應用程式首先處理已載入特定資料集的資料庫。這稱為預先填入資料庫。在 Room 2.2.0 及以上版本中,您可以使用 API 方法在初始化時,使用裝置檔案系統中預先封裝的資料庫檔案內容來預先填充 Room 資料庫。

從應用程式素材資源預先填入

如要從位於應用程式 assets/ 目錄任意位置的預先封裝資料庫檔案中預先填入 Room 資料庫,請先透過 RoomDatabase.Builder 物件呼叫 createFromAsset() 方法,再呼叫 build()

Kotlin

Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db")
    .createFromAsset("database/myapp.db")
    .build()

Java

Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db")
    .createFromAsset("database/myapp.db")
    .build();

createFromAsset() 方法接受字串引數,其中包含從 assets/ 目錄到預先封裝資料庫檔案的相對路徑。

從檔案系統預先填入

如要從位於裝置檔案系統任意位置的預先封裝資料庫檔案中,預先填入 Room 資料庫,而非應用程式的 assets/ 目錄,請先透過 RoomDatabase.Builder 物件呼叫 createFromFile() 方法,再呼叫 build()

Kotlin

Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db")
    .createFromFile(File("mypath"))
    .build()

Java

Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db")
    .createFromFile(new File("mypath"))
    .build();

createFromFile() 方法接受預先封裝資料庫檔案的 File 引數。Room 會建立指定檔案的副本,而非直接開啟,因此請確認您的應用程式具備該檔案的讀取權限。

處理納入預先封裝資料庫的遷移作業

預先封裝的資料庫檔案還可以變更 Room 資料庫處理備用遷移作業的方式。通常,如果啟用破壞性遷移作業,且 Room 必須在沒有遷移路徑的情況下執行遷移作業,則 Room 會捨棄資料庫中所有資料表,並建立具有目標版本指定結構定義的空白資料庫。不過,如果您納入的預先封裝資料庫檔案數量與目標版本相同,在執行破壞性遷移作業之後,Room 會嘗試將預先封裝的資料庫檔案內容,填入已經重新建立的資料庫。

如要進一步瞭解 Room 資料庫遷移作業,請參閱遷移 Room 資料庫

以下各節舉例說明了 Room 的實際運作方式。

範例:使用預先封裝的資料庫進行備用遷移

假設下列事項:

  • 您的應用程式定義了第 3 版的 Room 資料庫。
  • 裝置上已經安裝 第 2 版資料庫執行個體。
  • 存在第 3 版預先封裝的資料庫檔案。
  • 沒有實作從第 2 版到第 3 版的遷移路徑。
  • 已啟用破壞性遷移作業。

Kotlin

// Database class definition declaring version 3.
@Database(version = 3)
abstract class AppDatabase : RoomDatabase() {
    ...
}

// Destructive migrations are enabled and a prepackaged database
// is provided.
Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db")
    .createFromAsset("database/myapp.db")
    .fallbackToDestructiveMigration()
    .build()

Java

// Database class definition declaring version 3.
@Database(version = 3)
public abstract class AppDatabase extends RoomDatabase {
    ...
}

// Destructive migrations are enabled and a prepackaged database
// is provided.
Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db")
    .createFromAsset("database/myapp.db")
    .fallbackToDestructiveMigration()
    .build();

在這種情況下會發生下列情況:

  1. 由於應用程式中定義了第 3 版資料庫,而裝置上已經安裝的資料庫執行個體為第 2 版,因此必須遷移。
  2. 由於沒有實作從第 2 版到第 3 版的遷移計畫,因此這項遷移作業屬於備援遷移作業。
  3. 由於系統會呼叫 fallbackToDestructiveMigration() 建構工具方法,因此備用遷移作業具有破壞性。Room 會捨棄裝置上已經安裝的資料庫執行個體。
  4. 由於存在第 3 版預先封裝的資料庫檔案,因此 Room 會重新建立該資料庫,並填入預先封裝的資料庫檔案內容。另一方面,如果預先封裝的資料庫檔案為第 2 版,則 Room 會注意到其與目標版本不符,而且不會用於備份遷移作業。

範例:實作預先封裝的資料庫遷移作業

假設應用程式實作了從第 2 版到第 3 版的遷移路徑:

Kotlin

// Database class definition declaring version 3.
@Database(version = 3)
abstract class AppDatabase : RoomDatabase() {
    ...
}

// Migration path definition from version 2 to version 3.
val MIGRATION_2_3 = object : Migration(2, 3) {
    override fun migrate(database: SupportSQLiteDatabase) {
        ...
    }
}

// A prepackaged database is provided.
Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db")
    .createFromAsset("database/myapp.db")
    .addMigrations(MIGRATION_2_3)
    .build()

Java

// Database class definition declaring version 3.
@Database(version = 3)
public abstract class AppDatabase extends RoomDatabase {
    ...
}

// Migration path definition from version 2 to version 3.
static final Migration MIGRATION_2_3 = new Migration(2, 3) {
    @Override
    public void migrate(SupportSQLiteDatabase database) {
        ...
    }
};

// A prepackaged database is provided.
Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db")
    .createFromAsset("database/myapp.db")
    .addMigrations(MIGRATION_2_3)
    .build();

在這種情況下會發生下列情況:

  1. 由於應用程式中定義了第 3 版資料庫,而裝置上已經安裝的資料庫為第 2 版,因此必須遷移。
  2. 由於已經實作從第 2 版到第 3 版的遷移路徑,因此 Room 會執行定義的 migrate() 方法,將裝置上的資料庫執行個體更新為第 3 版,並保留資料庫中已有的資料。Room 不會使用預先封裝的資料庫檔案,因為 Room 只會在備用遷移作業時使用預先封裝的資料庫檔案。

範例:預先封裝資料庫的多步驟遷移

預先封裝的資料庫檔案還會影響包含多個步驟的遷移作業。假設下列情況:

  • 應用程式定義了第 4 版的 Room 資料庫。
  • 裝置上已經安裝 第 2 版資料庫執行個體。
  • 存在第 3 版預先封裝的資料庫檔案。
  • 已經實作從第 3 版到第 4 版遷移路徑,但沒有從第 2 版遷移至第 3 版。
  • 已啟用破壞性遷移作業。

Kotlin

// Database class definition declaring version 4.
@Database(version = 4)
abstract class AppDatabase : RoomDatabase() {
    ...
}

// Migration path definition from version 3 to version 4.
val MIGRATION_3_4 = object : Migration(3, 4) {
    override fun migrate(database: SupportSQLiteDatabase) {
        ...
    }
}

// Destructive migrations are enabled and a prepackaged database is
// provided.
Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db")
    .createFromAsset("database/myapp.db")
    .addMigrations(MIGRATION_3_4)
    .fallbackToDestructiveMigration()
    .build()

Java

// Database class definition declaring version 4.
@Database(version = 4)
public abstract class AppDatabase extends RoomDatabase {
    ...
}

// Migration path definition from version 3 to version 4.
static final Migration MIGRATION_3_4 = new Migration(3, 4) {
    @Override
    public void migrate(SupportSQLiteDatabase database) {
        ...
    }
};

// Destructive migrations are enabled and a prepackaged database is
// provided.
Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db")
    .createFromAsset("database/myapp.db")
    .addMigrations(MIGRATION_3_4)
    .fallbackToDestructiveMigration()
    .build();

在這種情況下會發生下列情況:

  1. 由於應用程式中定義了第 4 版資料庫,而裝置上已經安裝的資料庫執行個體為第 2 版,因此必須遷移。
  2. 由於沒有實作從第 2 版到第 3 版的遷移路徑,因此這項遷移作業屬於備援遷移作業。
  3. 由於系統會呼叫 fallbackToDestructiveMigration() 建構工具方法,因此備用遷移作業具有破壞性。Room 會捨棄裝置上的資料庫執行個體。
  4. 由於存在第 3 版預先封裝的資料庫檔案,因此 Room 會重新建立該資料庫,並填入預先封裝的資料庫檔案內容。
  5. 裝置上安裝的資料庫版本現在為第 3 版。但仍然低於應用程式中定義的版本,因此必須再次進行遷移。
  6. 由於已經實作從第 3 版到第 4 版的遷移路徑,因此 Room 會執行定義的 migrate() 方法,將裝置上的資料庫執行個體更新為第 4 版,並保留從第 3 版預先封裝的資料庫檔案中複製的資料。

其他資源

如要進一步瞭解如何預先填入 Room 資料庫,請參閱下列其他資源。

影片

網誌