Room 이란?
SQLite를 완벽히 활용하면서 데이터베이스 액세스가 가능하도록 SQLite에 추상화 계층을 제공하는 라이브러리
앱을 실행하는 기기에서 앱 데이터의 캐시를 만들 수 있고, 앱의 캐시를 통해 사용자는 인터넷 연결 여부와 관계없이
앱의 주요 정보를 확인할 수 있다.
Room을 사용하면 얻을수 있는 이점
- SQL 쿼리의 컴파일 시간 확인
- 반복적이고 오류가 발생하기 쉬운 상용구 코드를 최소화하는 편의 주석
- 간소화된 데이터베이스 이전 경로
Room의 기본 요소
- 데이터베이스 클래스: 데이터베이스를 보유하고 앱의 영구 데이터와의 기본 연결을 위한 기본 액세스 포인트 역할을 합니다.
- 데이터 항목: 앱 데이터베이스의 테이블을 나타냅니다.
- 데이터 액세스 객체(DAO): 앱이 데이터베이스의 데이터를 쿼리, 업데이트, 삽입, 삭제하는 데 사용할 수 있는 메서드를 제공합니다.
라고 android 문서에 나와있다.
Room 라이브러리 아키텍쳐 다이어그램
데이터 항목 정의
운동 정보를 저장하기 위한 데이터 항목을 정의해보자.
@Entity 어노테이션을 사용해주어야 한다.
tableName 속성을 설정해주지 않으면 class의 이름이 tableName으로 지정된다.
마찬가지로 열 이름을 변수 이름과 다르게 하려면, @ColumnInfo 어노테이션을 추가하고, name 속성을 설정한다.
기본 키 정의를 하려면 @Primary 어노테이션을 기본 키로 지정할 열에 추가해준다.
기본 키를 자동으로 증가시키려면 autoGenerate 속성을 true로 설정해주면 된다.
참고: SQLite의 테이블 및 열 이름은 대소문자를 구분하지 않는다.
@Entity(tableName = "exercises")
data class Exercise(
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id") var exerciseId:Long?,
var name: String,
var numberOfSet: Int,
)
데이터 액세스 객체(DAO)
DAO란?
Data Access Object
앱 데이터베이스에 관한 추상 액세스 권한을 제공하는 메서드가 포함된 객체
즉, 데이터에 접근하기 위해 사용하는 객체
DAO 메서드의 두가지 유형
- 편의 메서드: SQL 코드 작성 없이 데이터베이스에서 행을 삽입하고 업데이트하고 삭제할 수 있습니다.
- 쿼리 메서드: 자체 SQL 쿼리를 작성하여 데이터베이스와 상호작용할 수 있습니다.
라고 android 문서에 나와있다.
편의 메서드
삽입(@Insert)
데이터베이스의 테이블에 매개변수를 삽입하는 메서드를 정의할 수 있다.
@Insert 메서드의 각 매개변수는
@Entity 어노테이션이 달린 Room 데이터 항목 클래스이거나,
데이터 항목 클래스 인스턴스의 컬렉션이어야 한다.
참고: @Insert 메서드가 단일 매개변수를 수신하면 Long 값을 반환할 수 있고 이 값은 삽입된 항목의 새 rowId 이다.
충돌 처리방식을 설정하려면 onConfilct 속성을 설정해준다.
OnConflictStrategy.REPLACE 로 설정하면, 충돌이 일어났을 때, 새로운 값으로 변경한다는 뜻이다.
다른 충돌 처리방식 속성은 문서를 확인하자.
http:// https://developer.android.com/reference/android/arch/persistence/room/OnConflictStrategy
@Dao
interface ExerciseDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertExercise(exercise: Exercise):Long
}
업데이트(@Update)
@Update 어노테이션을 사용하면 테이블에서 특정 행을 업데이트 하는 메서드를 정의할 수 있다.
@Insert 메서드와 동일하게, 데이터 항목 인스턴스( Ex) 위에서 정의한 Exercise data Class ) 를 매개변수로 허용한다.
기본 키(@Primary)를 사용하여 전달된 항목 인스턴스를 데이터베이스의 행과 일치시킨다.
기본 키가 같은 행이 없으면, Room에서는 아무것도 변경하지 않는다.
참고 : @Update 메서드는 성공적으로 업데이트된 행 수를 나타내는 int 값을 선택적으로 반환할 수 있다.
@Dao
interface ExerciseDao {
@Update
fun updateExercise(exercise: Exercise)
}
삭제(@Delete)
@Delete 어노테이션을 사용하면 테이블에서 특정 행을 삭제하는 메서드를 정의할 수 있다.
다른 편의 메소드들과 동일하게, 데이터 항목 인스턴스를 매개변수로 허용한다.
기본 키(@Primary)를 사용하여 전달된 항목 인스턴스를 데이터베이스의 행과 일치시킨다.
기본 키가 같은 행이 없으면, Room에서는 아무것도 변경하지 않는다.
참고: @Delete 메서드는 성공적으로 삭제된 행 수를 나타내는 int 값을 선택적으로 반환할 수 있다.
쿼리 메서드
@Query 어노테이션을 사용하여 DAO 메서드로 사용할 수 있다.
쿼리 메서드는 데이트베이스에서 좀 더 복잡한 삽입, 업데이트, 삭제를 실행해야 할 때 사용한다.
Room은 컴파일 시간에 SQL 쿼리를 검증한다. 즉, 쿼리에 문제가 있으면 런타임 실패가 아닌 컴파일 오류가 발생한다.
이런 형태로 필요한 메서드를 정의하여 사용할 수 있다.
@Query("SELECT * FROM exercises")
fun getExercise(): LiveData<List<Exercise>>
@Query("SELECT * FROM exercises where exerciseId = :id")
suspend fun getExerciseById(id:Long):Exercise
@Transaction
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun createExercise(exercise: Exercise, sets: List<ExerciseSet>):Long{
val exerciseId = insertExercise(exercise)
sets.map {
it.apply { parentExerciseId = exerciseId }
}.also { insertSets(it) }
return exerciseId
}
세번째 메서드인 createExercise 메서드는 1:N RelationShip 관계를 가진 테이블 두개에 한번에 Insert하는 메서드인데, 이 메서드와 Room에서 객체 간 관계를 정의하는 법은 글을 따로 추가하도록 할 것이다.
데이터베이스
AppDatabase 클래스를 정의할 것이다. 이 클래스는 데이터베이스 구성을 정의하고 영구 데이터에 대한
앱의 기본 액세스 포인트 역할을 한다.
데이터베이스 클래스는 다음 조건을 충족해야 한다.
- 클래스에는 데이터베이스와 연결된 데이터 항목을 모두 나열하는 entities 배열이 포함된 @Database 어노테이션(주석)이 달려야 합니다.
- 클래스는 RoomDatabase를 확장하는 추상 클래스여야 합니다.
- 데이터베이스와 연결된 각 DAO 클래스에서 데이터베이스 클래스는 인수가 0개이고 DAO 클래스의 인스턴스를 반환하는 추상 메서드를 정의해야 합니다.
라고 Android 공식 문서에 나와있다.
@Database(entities = [Exercise::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun ExerciseDao(): ExerciseDao
}
참고: 앱이 단일 프로세스에서 실행되면 AppDatabase 객체를 인스턴스화할 때 싱글톤 디자인 패턴을 따라야 합니다. 각 RoomDatabase 인스턴스는 리소스를 상당히 많이 소비하며 단일 프로세스 내에서 여러 인스턴스에 액세스해야 하는 경우는 거의 없습니다.
앱이 여러 프로세스에서 실행되는 경우 데이터베이스 빌더 호출에 enableMultiInstanceInvalidation()을 포함하세요. 이렇게 하면 각 프로세스에 AppDatabase 인스턴스가 있을 때 한 프로세스에서 공유 데이터베이스 파일을 무효화할 수 있으며 이 무효화는 다른 프로세스 내의 AppDatabase 인스턴스로 자동 전파됩니다.
'개인공부 > android' 카테고리의 다른 글
[Kotlin] Coroutine을 이용한 간단한 타이머 (0) | 2022.02.16 |
---|---|
[Kotlin] Fragment already added: DialogFragment (0) | 2022.02.03 |
[Kotlin] Adpater에서 Room Database Delete Event 받기 (0) | 2022.02.03 |
[Kotlin] Coroutines (코루틴) (0) | 2022.02.01 |
Android Icon drawable 추가하기 (Vector Asset) (0) | 2022.01.27 |