Room Database
안드로이드 아키텍처 컴포넌트에 속하는 Room 라이브러리는 SQLite에 대한 추상화 레이어를 제공하여 원활한 데이터베이스 액세스를 지원하는 동시에 SQLite를 완벽히 활용한다.
build.gradle 파일에 다음 dependencies를 추가한다. (Kotlin 사용시)
dependencies {
def room_version = "2.3.0"
implementation "androidx.room:room-runtime:$room_version"
// To use Kotlin annotation processing tool (kapt)
kapt "androidx.room:room-compiler:$room_version"
// To use Kotlin Symbolic Processing (KSP)
ksp "androidx.room:room-compiler:$room_version"
// optional - Kotlin Extensions and Coroutines support for Room
implementation "androidx.room:room-ktx:$room_version"
// optional - Test helpers
testImplementation "androidx.room:room-testing:$room_version"
}
Room 주요 구성요소
룸 데이터베이스(Room Database) : 데이터베이스를 보유하고 앱의 지속적인 관계형 데이터의 기본 연결을 위한 기본 액세스 포인트 역할을 하는 데이터베이스 클래스이다.
데이터 접근 객체(Data Access Object) : 데이터베이스에 접근하여 수행할 작업을 메소드 형태로 정의한다.
엔티티(Entity) : 데이터베이스 내의 테이블, DB에 저장할 데이터 형식을 정의한다.
앱은 Room 데이터베이스를 사용하여 데이터베이스와 연결된 데이터 액세스 개체 또는 DAO를 가져온다. 그런 다음 앱은 각 DAO를 사용하여 데이터베이스에서 항목을 가져오고 항목의 변경사항을 다시 데이터베이스에 저장한다. 마지막으로 앱은 항목을 사용하여 데이터베이스 내의 테이블 열에 해당하는 값을 가져오고 설정한다.
간단한 예제 구현하기
Entity
@Entity
class BookInfoEntity (
val authors:Array<String>?,
@ColumnInfo(collate = ColumnInfo.NOCASE) val title: String,
val contents: String?,
val datetime: String?,
@PrimaryKey @ColumnInfo(name="isbn") val isbn:String,
val price:Int?,
val publisher:String?,
@SerializedName("sale_price") val salePrice:Int?,
val status:String?,
val thumbnail:String?,
val url:String?,
) : Serializable
@Entity 어노테이션과 함께 데이터베이스 내의 릴레이션을 생성, 하나 이상의 필드를 기본 키로 정의해야 한다. 필드가 하나만 있는 경우에도 @PrimaryKey 주석을 사용하여 필드에 주석을 달아야 합니다. 또한 Room에서 항목에 자동 ID를 할당하게 하려면 @PrimaryKey의 autoGenerate 속성을 설정하면 된다. 항목에 복합 기본 키가 있으면 @Entity 주석의 primaryKeys 속성을 사용할 수 있다.
기본적으로 Room은 클래스 이름을 데이터베이스 테이블 이름으로 사용하는데 테이블의 이름을 다르게 지정하려면 @Entity 주석의 tableName 속성을 설정하자
@Entity(tableName = "bookinfo")
class BookInfoEntity (
...
)
Dao(Data Access Object)
@Dao 어노테이션과 함께 데이터베이스에 접근하여 수행할 작업들을 메서드 형태로 지정한다. 이 메소드들은 interface 내에 포함되므로 모두 추상 메소드들이다. 쿼리 빌더 또는 직접 쿼리 대신 DAO 클래스를 사용하여 데이터베이스에 액세스하면 데이터베이스 아키텍처의 다양한 구성요소를 분리할 수 있다.
DAO 메서드를 만들고 @Insert 주석을 달 때 Room은 단일 트랜잭션으로 모든 매개변수를 데이터베이스에 삽입하는 구현을 생성한다. onConflict 설정을 통해 만약 데이터베이스 내에 중복된 투플 값이 존재함에도 불구하고 데이터를 추가한다면 그 값 위에 바로 덮어 씌운다.
@Dao
interface BookInfoDao{
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun add(info:BookInfoEntity)
...
}
Update 편의 메서드는 매개변수로 제공된 항목 세트를 데이터베이스에서 수정한다. 이 메서드는 각 항목의 기본 키와 일치하는 쿼리를 사용한다.
@Dao
interface BookInfoDao{
@Update
fun update(bookinfo: BookInfoEntity)
...
}
Delete 편의 메서드는 매개변수로 제공된 항목 세트를 데이터베이스에서 삭제한다. 이 메서드는 기본 키를 사용하여 삭제할 항목을 찾는다.
@Dao
interface BookInfoDao{
@Delete
fun delete(bookinfo: BookInfoEntity)
...
}
@Query는 DAO 클래스에서 사용하는 기본 주석으로 데이터베이스에서 읽기/쓰기 작업을 실행할 수 있다. 각 @Query 메서드는 컴파일 시간에 확인되므로 쿼리에 문제가 있으면 런타임 오류 대신 컴파일 오류가 발생한다.
@Dao
interface BookInfoDao{
@Query("SELECT * FROM bookinfo")
fun getAllBookList(): Flowable<List<BookInfoEntity>>
...
}
Database
@Database 어노테이션과 함께 데이터베이스의 전체적인 소유자 역할을 하고 있으며 앞에서 생성한 Entity, DAO 클래스를 통합적으로 묶어 데이터베이스를 생성하거나 버전 관리를 진행한다.
@Database(entities = arrayOf(BookInfo::class), version = 1)
@TypeConverters(Converters::class)
abstract class BookInfoDatabase:RoomDatabase() {
abstract fun bookInfoDao():BookInfoDao
}
@Module
class LocalDataModule {
@Provides
@Singleton
fun provideBookInfoDao(db:BookInfoDatabase):BookInfoDao
= db.bookInfoDao()
@Provides
@Singleton
fun provideDatabase(@Named("appContext")context: Context):BookInfoDatabase
= Room.databaseBuilder(context,
BookInfoDatabase::class.java, "book_info.db").build()
}
References