Room 엔티티 클래스와 기본 데이터베이스 테이블을 수정해야 할 경우, 기기 내에 이미 존재하는 데이터베이스의 유저 데이터를 보존하는 것이 중요.
Room은 자동 마이그레이션과 수동 마이그레이션 모두 지원.
Room은 2.4.0-alpha01 버전 이상에서 자동 마이그레이션을 지원하며 이보다 낮은 버전을 사용할 경우 수동으로 마이그레이션을 정의해야 함.
두 개의 데이터베이스 버전 간 자동 마이그레이션을 선언하려면 @Database
의 autoMigrations 속성에 @AutoMigration
주석을 추가
// Database class before the version update.
@Database(
version = 1,
entities = [User::class]
)
abstract class AppDatabase : RoomDatabase() {
...
}
// Database class after the version update.
@Database(
version = 2,
entities = [User::class],
autoMigrations = [
AutoMigration (from = 1, to = 2)
]
)
abstract class AppDatabase : RoomDatabase() {
...
}
❗ exportSchema가 false로 설정되어 있거나 새 버전 번호로 데이터베이스를 아직 컴파일하지 않았다면 자동 마이그레이션은 실패.
Room은 모호한 스키마 변경이 발생할 경우 이름이 변경된건지 삭제된것인지 판단할 수 없음. 이 때 컴파일 에러가 발생하고 AutoMigrationSpec을 구현하도록 요청함.
AutoMigrationSpec을 사용하여 Room에 올바른 마이그레이션 경로를 생성할 수 있도록 정보를 제공해야 함.
@DeleteTable
@RenameTable
@DeleteColumn
@RenameColumn
자동 마이그레이션에서 AutoMigrationSpec 구현을 사용하려면 @AutoMigration
주석에서 spec 속성을 설정해야 함.
@Database(
version = 2,
entities = [User::class],
autoMigrations = [
AutoMigration (
from = 1,
to = 2,
spec = AppDatabase.MyAutoMigration::class
)
]
)
abstract class AppDatabase : RoomDatabase() {
@RenameTable(fromTableName = "User", toTableName = "AppUser")
class MyAutoMigration : AutoMigrationSpec
...
}
수동 마이그레이션은 복잡한 스키마 변경이 필요한 경우 사용됨.
예) 테이블의 데이터를 두 개의 테이블로 분할하기로 결정한 경우 등
val MIGRATION_1_2 = object : Migration(1, 2) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("CREATE TABLE `Fruit` (`id` INTEGER, `name` TEXT, " +
"PRIMARY KEY(`id`))")
}
}
val MIGRATION_2_3 = object : Migration(2, 3) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Book ADD COLUMN pub_year INTEGER")
}
}
Room.databaseBuilder(applicationContext, MyDb::class.java, "database-name")
.addMigrations(MIGRATION_1_2, MIGRATION_2_3).build()
마이그레이션 경로를 정의할 때 일부 버전은 자동 마이그레이션을 사용하고 다른 버전은 수동 마이그레이션을 사용할 수 있음.
동일한 버전에 대해 자동 마이그레이션과 수동 마이그레이션을 모두 정의한 경우 Room은 수동 마이그레이션을 이용함.