ANDROID

Android - 로컬DB편 : Room

찰리누나 2022. 1. 13. 04:45

 

공식 문서 : https://developer.android.com/training/data-storage/room?hl=ko 

 

Room을 사용하여 로컬 데이터베이스에 데이터 저장  |  Android 개발자  |  Android Developers

Room 라이브러리를 사용하여 더 쉽게 데이터를 유지하는 방법 알아보기

developer.android.com

 

 

안드로이드 Room 

 

안드로이드 Room은 로컬 DB(기기의 내장 DB) 를 사용하기 위한 라이브러리로, 앱에서 스마트폰의 내장 DB에 데이터를 저장하기 위해서 사용한다. 예전에는 SQLite라는 것을 사용하였으나 지금은 Room을 사용하기를 권장하고 있다. Room은 SQLite를 활용하여 객체를 매핑해주는 역할을 한다. Room을 ORM 라이브러리라고 하는데, ORM은 Object Relational Mapping의 약자로 객체와 관계형 데이터베이스의 데이터를 자동으로 자바, 또는 코틀린 객체로 매핑(*연결) 해 주는 것을 뜻한다.

 

Room은 @Entity, @Dao, @Database 라는 세 가지 주요 구성요소를 가진다.

 

@Entity :
 데이터베이스에서의 '테이블'에 해당한다. 테이블명, 칼럼 명, 칼럼 타입, 기본 키, 외래 키 등을 정의할 수 있는 다양한 *어노테이션을 제공한다.

@Dao :
 데이터베이스에 접근하는 데에 필요한 메서드를 포함한다. 즉, 삽입, 삭제, 업데이트, 쿼리 등을 정의할 수 있는 어노테이션을 제공한다.

@Database : 
RoomDatabase 클래스를 상속받는 abstract class이다. 이 어노테이션 안에는 데이터베이스와 관련된 Entity 리스트를 포함해야 하며, @dao를 반환하는 abstract method를 포함해야 한다. 

*어노테이션 : @가 붙은 메타데이터. 데이터를 설명하는 데이터를 뜻한다.

 

 

앱은 Room Database에서 DAO를 가져오고, DAO를 사용해 Entity에 접근한다. 그 다음 DAO의 메서드를 이용하여 Entity의 변경사항들을 가져온 뒤 다시 데이터베이스에 적용한다. 아래 그림이 공식 문서에서 설명한 내용이다. 

 

 

안드로이드 코드랩에서 쉽게 실습해볼 수 있다. : https://developer.android.com/codelabs/android-room-with-a-view-kotlin#0 

 

뷰를 사용한 Android Room - Kotlin  |  Android 개발자  |  Android Developers

이 Codelab에서는 Kotlin 코루틴과 함께 Android 아키텍처 구성요소(RoomDatabase, Entity, DAO, AndroidViewModel, LiveData)를 사용하는 Android 앱을 Kotlin으로 빌드합니다. 이 샘플 앱은 단어 목록을 Room 데이터베이스

developer.android.com

 

안드로이드 룸을 사용하려면 gradle을 추가해야 하는데, 액티비티에서 Room이라고 입력한 뒤 Alt+Enter를 이용해 'Add dependency on androidx.room:room-runtime'을 추가할 수 있다. 

 

dependencies {
    val roomVersion = "2.3.0"

    implementation("androidx.room:room-runtime:$roomVersion")
    annotationProcessor("androidx.room:room-compiler:$roomVersion")

    // To use Kotlin annotation processing tool (kapt)
    kapt("androidx.room:room-compiler:$roomVersion")
    // To use Kotlin Symbolic Processing (KSP)
    ksp("androidx.room:room-compiler:$roomVersion")

    // optional - Kotlin Extensions and Coroutines support for Room
    implementation("androidx.room:room-ktx:$roomVersion")

    // optional - RxJava2 support for Room
    implementation("androidx.room:room-rxjava2:$roomVersion")

    // optional - RxJava3 support for Room
    implementation("androidx.room:room-rxjava3:$roomVersion")

    // optional - Guava support for Room, including Optional and ListenableFuture
    implementation("androidx.room:room-guava:$roomVersion")

    // optional - Test helpers
    testImplementation("androidx.room:room-testing:$roomVersion")

    // optional - Paging 3 Integration
    implementation("androidx.room:room-paging:2.4.0-rc01")
}

▲ 코틀린을 사용할 경우 kapt 플러그인을 함께 사용해야 한다. plugins에 id 'kotlin-kapt'를 추가해주면 된다. 

 

 

■ Entity 

 

- Entity는 한국어로 '개체' 이다. 개체는 Object(객체)보다 더 큰 개념으로 생각하면 된다. 데이터베이스 테이블을 만드는 방식과 비슷하게 생성할 수 있다. data class를 만든 뒤 @Entity 어노테이션을 붙여주고, 로컬 db에 저장하고 싶은 속성의 변수 이름과 타입을 정의하면 된다.

- 안드로이드 database 내의 테이블을 자바, 코틀린으로 나타낸 것이다. 

 @Entity
    data class User(
        @PrimaryKey val uid: Int,
        @ColumnInfo(name = "first_name") val firstName: String?,
        @ColumnInfo(name = "last_name") val lastName: String?
    )
@Entity(tableName = “테이블 이름”)
대소문자를 구분하지 않으며, 테이블 이름을 설정할 수 있다. 기본값은 Class 명과 동일하게 설정된다. Serializable을 implements하여 다른 클래스들 처럼 Intent에 담아서 이동시킬 수 있다. 

@PrimaryKey
선언한 변수에 기본키를 설정한다. sql db와 마찬가지로 기본키는 중복을 허용하지 않으며, 유니크해야 한다. autoGenerate=true로 설정하여 자동으로 기본키를 생성할 수 있다.

@ColumnInfo
테이블 컬럼 명을 설정한다. 기본 값은 멤버 변수의 변수명이다.

@Ignore
DB에 실제로 저장되지 않으나 클래스에 포함해야 하는 멤버 변수의 경우 @Ignore 어노테이션을 사용하면, 해당 변수가 db에 저장되지 않도록 할 수 있다.

@Realtion
선언된 테이블 관계에서 매칭되는 외래키를 설정할 수 있다.

 

■ DAO

 

- Data Acess Object. 데이터에 직접 접근할 수 있는 메서드를 정의한 *인터페이스이다. 

 @Dao
    interface UserDao {
        @Query("SELECT * FROM user")
        fun getAll(): List<User>

        @Query("SELECT * FROM user WHERE uid IN (:userIds)")
        fun loadAllByIds(userIds: IntArray): List<User>

        @Query("SELECT * FROM user WHERE first_name LIKE :first AND " +
               "last_name LIKE :last LIMIT 1")
        fun findByName(first: String, last: String): User

        @Insert
        fun insertAll(vararg users: User)

        @Delete
        fun delete(user: User)
    }
    
@Query
SQL Query문 역할을 한다. @Query("쿼리문") 을 사용해 db에서 쿼리문에 해당하는 작업을 실행할 수 있다. :컬럼 명 을 붙여 쿼리에 매개변수를 전달할 수 있다. 컴파일 시 쿼리가 처리될 때, 안드로이드 Room은 :컬럼명 바인드 매개변수와 메서드의 파라미터 변수를 일치시킨다.

@Delete
파라미터로 넘겨 받은 데이터를 테이블에서 삭제한다.

@Insert
데이터를 테이블에 삽입한다. (onConflict = OnConflictStrategy.REPLACE) 를 사용하면, 

@Update
테이블 데이터를 수정한다.

-https://developer.android.com/training/data-storage/room/accessing-data?hl=ko 에서 더 많은 어노테이션을 확인할 수 있다.

 

 

■ Database

 

-Database holder를 포함하며, RoomDatabase를 상속받는 추상 클래스이다. 또한 abstract의 Dao를 가지고 있다. 

런타임 시 Room.databaseBuilder() 나 Room.inMemoryDatabaseBuilder() 를 호출해 DB 인스턴스를 가져올 수 있다. 

 @Database(entities = arrayOf(User::class), version = 1)
    abstract class AppDatabase : RoomDatabase() {
        abstract fun userDao(): UserDao
    }
@Database
해당 클래스가 Database임을 알려준다. 

entities = arrayOf(User::class) 
하나의 데이터베이스에 여러개의 Entity를 추가할 경우 arrayOf( )를 이용한다.
entities는 이 db에 어떤 테이블들이 들어있는지를 명시한다. 

version
앱을 업데이트 할 때, 기존 Entity 구조를 변경해야 하는 일이 발생할 경우 구분해주는 역할을 한다. 


 

 

■ 데이터베이스 인스턴스 가져오기(Activity에서의 Room 사용)

 val db = Room.databaseBuilder(
                applicationContext,
                AppDatabase::class.java, "database-name"
            ).build()

 

* 나를 위한 개발 순서 필기

- 그래들 설정 -> @Entity Class 생성 -> @Dao interface 생성 -> @Database abstract class 생성 -> Room 사용(db생성->데이터 읽고 사용하는 thread)