서론
기존에 Android에서 DB를 활용하기 위해 SQLite를 사용했었다. Kotlin 공부를 하던 중 Room을 활용하면 SQLite를 보다 쉽게 활용할 수 있다고 하여 정리해 보았다.
Room이란?
Room은 스마트폰 내장(로컬) DB에 데이터를 저장하기 위해 사용되는 라이브러리다.
평소 사용자가 메모 저장, 일정 저장 등 사용자의 데이터를 내장 DB에 저장하는 경우가 있다. 이때, SQLite라는 DB를 이용해 데이터를 저장했는데 이를 효과적으로 사용하기 위해 등장한 것이 Room이다.
SQLite의 단점에 대해서 developer에서 아래와 같이 언급했다.
Room을 쉽게 설명하자면, SQLite의 뒤를 이을 새로운 DB가 등장한 게 아니라, SQLite를 보다 간단하게 처리할 수 있도록 도와주는 라이브러리이다.
SQLite를 활용해서 객체 매핑을 해주는 역할을 하고 현재 구글에서도 SQLite 대신 Room 사용을 권장하고 있는 추세이다.
Room? Realm?
Android에서 DB관련 라이브러리로 자주 사용되는 Room과 Realm은 뭐가 다를까?
실제로 Realm은 사용해 본 경험이 없어 차이점을 조사해 보았다.
- Room : 비교적 낮은 용량을 차지하고, sql 문법을 알아야 함
- Realm : 용량이 비교적 크고, sql 문법을 몰라도 사용이 가능함
Room은 Sqlite의 모든 기능을 사용할 수 있고, 기존에 sql 문법에 대한 이해가 있는 사람이라면 쉽게 접근할 수 있다.
Realm의 경우 sql 문법을 몰라도 사용이 가능하고, 문서가 많고, 메서드도 많다는 장점이 있지만, 용량이 크다는 단점이 있다.
만약, 처리해야 할 데이터의 양이 많다면 Realm을 사용하는 것이 적합하다고 생각하고, 그 외의 경우 Room이 효율적이라고 본다. (구글에서 밀어주기도 하니깐)
Room의 장점
먼저, 로컬 DB를 사용할 때 장점은 기기가 네트워크에 액세스 할 수 없을 때도 사용자가 오프라인 상태로 계속 콘텐츠를 탐색할 수 있도록 관련 데이터를 캐시 하는 것이다. Room 라이브러리는 SQLite를 완벽하게 활용하면서 원활한 데이터베이스 액세스가 가능하도록 SQLite에 추상화 계층을 제공한다.
- SQL 쿼리의 컴파일 시간 확인 가능
- 반복적이고 오류가 발생하기 쉬운 상용구 코드를 최소화하는 주석
- 간소화된 데이터베이스 이전 경로
위의 점을 고려할 때 SQLite를 직접 사용하는 대신 Room을 사용하는 것이 효율적이다.
Room의 기본 구조
- Database : DB를 보유하고 앱의 영구 데이터와의 기본 연결을 위한 기본 액세스 포인트 역할, Singleton 클래스로 구현하는 게 일반적
- Entity : 데이터 베이스의 테이블에 해당하는 것으로, 클래스 형태로 정의하며 클래스 내 속성 값이 곧 테이블의 컬럼(필드)이 됨
- DAO(Data Access Objects) : 테이블의 데이터에 접근할 수 있는 인터페이스를 정의한 클래스로 데이터 삽입, 삭제, 수정, 불러오기 등의 메서드를 정의함
Sample Code
build.gradle - 라이브러리 추가
dependencies {
def room_version = "2.5.0"
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version"
}
User.kt - Data class / Entity
data class User(
@PrimaryKey val uid: Int, //기본키
@ColumnInfo(name = "first_name") val firstName: String?,
@ColumnInfo(name = "last_name") val lastName: String?
)
UserDao.kt - DAO class
@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)
}
AppDatabase.kt - Database class (추상 클래스)
@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}
- 데이터 베이스 클래스에는 @Database 어노테이션과, 데이터 항목 표시를 위한 entities 배열이 포함되어야 한다.
- 클래스는 반드시 RoomDatabase를 확장하는 추상 클래스여야 한다.
- 데이터베이스와 연결된 각 DAO 클래스에서 데이터베이스 클래스는 인수가 0개이고 DAO 클래스의 인스턴스를 반환하는 추상 메서드를 정의해야 한다.
DB 사용
val db = Room.databaseBuilder(
applicationContext,
AppDatabase::class.java, "database-name"
).build()
val userDao = db.userDao()
val users: List<User> = userDao.getAll()
여기까지가 공식 문서에서 설명하는 내용이다. 하지만 참고 부분을 확인해 보면
데이터 베이스 객체를 싱글톤으로 구현하라고 권장하는 내용이다.
Database Singleton
@Database(entities = [User::class], version = 1)
abstract class UserDatabase: RoomDatabase() {
abstract fun userDao(): UserDao
companion object {
private var instance: UserDatabase? = null
@Synchronized // 하나의 스레드만 접근하도록
fun getInstance(context: Context): UserDatabase? {
if (instance == null) {
synchronized(UserDatabase::class){
instance = Room.databaseBuilder(
context.applicationContext,
UserDatabase::class.java,
"user-database"
).build()
}
}
return instance
}
}
}
위와 같이 companion object로 객체를 선언하여 사용하면 된다.
주의할 점은 객체 생성 시 context, database 클래스, database 이름을 전달해 주는데, 이름은 다른 db와 다르게 작성해주어야 한다.
Singleton 패턴 DB 사용 예시
val db = UserDatabase.getInstance(applicationContext)
CoroutineScope(Dispatchers.IO).launch { // 비동기 실행
val userDao = db.userDao()
val users : List<User> = userDao.getAll()
}
스레드 부하를 방지하기 위해 코루틴을 활용하여 비동기 실행
마치며
오늘은 SQLite를 보다 효율적으로 사용할 수 있도록 도와주는 Room 라이브러리에 대해 정리해 보았다.
공부하다 보니 Room을 효과적으로 사용하기 위해 Coroutine, Singleton pattern, DI 등 부족한 부분을 추가로 공부해야 된다고 느꼈다...
Migration 방법도 따로 있는 것 같던데 앞으로 공부해서 정리해보려 한다.
참고
Room을 사용하여 로컬 데이터베이스에 데이터 저장 | Android 개발자 | Android Developers
Room 라이브러리를 사용하여 더 쉽게 데이터를 유지하는 방법 알아보기
developer.android.com