🎉 개요
Database를 사용하다보면 필연적으로 데이터 베이스 스키마를 변경하는 상황이 발생합니다. Room은 데이터 베이스 스키마가 변경되면 version을 올려줘야 합니다. 이 때, 데이터 베이스를 마이 그레이션 할 수 있는 방법을 소개하겠습니다.
🎉 Migration
1️⃣ Version Up + fallbackToDestructiveMigration( )
가장 기본적으로 Migraion할 수 있는 방법은 Version을 올리고 fallbackToDestructiveMigration( ) 메소드를 사용하는 것입니다. 하지만 이렇게 할 경우 기존의 데이터가 모두 삭제된다는 치명적인 단점이 있습니다.
- fallbackToDestructiveMigration( )
데이터 베이스 스키마가 변경되었을 때 기존의 데이터 베이스와 데이터를 모두 삭제하고 새로운 스키마를 만듭니다.
Room은 앱이 실행될 때 데이터베이스의 스키마 버전을 체크하고 이전 버전과 현재 버전이 다를 경우 오류를 발생시킵니다. 이 때,개발자가 임의로 버전을 올려주었을 때 fallbackToDestructiveMigration( ) 메소드를 사용하지 않으면 IllegalStateException 오류를 발생시킵니다.
2️⃣ Migration Class
기존의 데이터를 보존하기 위한 방법으로 Migration 클래스를 상속하는 Class를 생성하면 됩니다. 아래 예시는 변경하고 싶은 버전을 매개 변수로 전달하고 변경되는 데이터 베이스 스키마를 Query로 전달합니다.
val MIGRATION_1_2 = object : Migration(1,2){
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("CREATE TABLE `text_table2` " +
"(`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `text2` TEXT NOT NULL)")
}
}
- .addMigraion( ) 메소드에 Migraion Class를 전달했습니다.
- @Database 어노테이션의 데이터 베이스 버전 또한 Migration하려는 버전과 일치해야 합니다.
- 하지만 Migraion Class를 생성할 경우 사용자가 변경하려는 스키마의 Query를 반드시 작성해줘야 합니다.
2️⃣ Auto Migration
Room 2.4.0-alpha01 Version 부터는 오토 마이그레이션 기능을 활용해 사용자가 직접 스키마의 변경 사항을 정확히 명시해주지 않아도 컬럼 추가/삭제, 테이블 추가 같은 동작인 Room이 자동으로 마이그레이션을 진행합니다.
📕 AutoMigration 사용법
- App 수준의 build.gradle 파일에 다음 구문을 추가합니다.
kapt {
arguments {
arg("room.schemaLocation", "$projectDir/schemas")
}
}
- 간단한 변경 사항 마이그레이션
아래와 같이 Database Class의 @Database 어노테이션의 version을 증가 시키고 autoMigrations에 마이그레이션 될 버전 정보를 입력해 줍니다.
@Database(
entities = [TextEntity::class],
version = 1,
autoMigrations = [
AutoMigration(from = 2, to = 3)
]
)
abstract class TextDatabase : RoomDatabase(){
abstract fun textDao() : TextDao
companion object {
@Volatile
private var INSTANCE : TextDatabase? = null
fun getDatabase(
context: Context
) : TextDatabase {
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
TextDatabase::class.java,
"text_database"
).build()
INSTANCE = instance
instance
}
}
}
}
- 복잡한 변경 사항 마이그레이션
테이블 또는 컬럼의 이름이 변경되는 경우 Room은 이름이 변경된건지 삭제 된건지 판단하지 못합니다. 이 경우에는 AutoMigrationSpec Class를 통해 아래 아노테이션 중 하나 이상을 사용해 구현할 수 있습니다.- @Deletetable(tableName)
- @RenameTable(fromTable, toTableName)
- @DeleteColumn(tableName, columnName)
- @RenameColumn(tablename, froColumnName, toColumnName)
package kr.co.lion.automigration.db
import android.content.Context
import androidx.room.*
import androidx.room.migration.AutoMigrationSpec
@Database(
entities = [TextEntity::class],
version = 1,
autoMigrations = [
AutoMigration(from = 2, to = 3,
spec = TextDatabase2.deleteOldTable::class,
)
]
)
abstract class TextDatabase2 : RoomDatabase(){
abstract fun textDao() : TextDao
@DeleteTable(tableName = "text_table")
class deleteOldTable
@RenameTable(fromTableName = "text_table", toTableName = "new_text_table")
class renameTable
@DeleteColumn(tableName = "text_table", columnName = "text")
class deleteOldColumn
@RenameColumn(tableName = "text_table", fromColumnName = "text2", toColumnName = "newText")
class renameOldColumn
companion object {
@Volatile
private var INSTANCE : TextDatabase? = null
fun getDatabase(
context: Context
) : TextDatabase {
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
TextDatabase::class.java,
"text_database"
).build()
INSTANCE = instance
instance
}
}
}
}
'Android' 카테고리의 다른 글
Room Like + StateFlow debouce와 Throttle (0) | 2024.03.31 |
---|---|
[Android] 프로퍼티의 초기화 시점이 중요한 이유! (0) | 2024.01.28 |
[Android] Room TypeConverter (0) | 2024.01.21 |
[Android] Room Database (0) | 2024.01.21 |
[Android] Jetpack WorkManager (0) | 2024.01.07 |