[Android] SQLite vs Room

2025. 2. 3. 10:57·Android/Study

로컬 저장소는 네트워크와 무관하게 데이터를 저장하는 공간이다

대표적으로 SQLite와 Room이 있고 이 두가지 방식의 차이점과 사용법을 정리해보려고 한다 🧐

특정 기능에 대해서만 궁금한 사람들은 목차를 클릭해서 빠르게 확인해보시길!

✏️ 로컬 저장소란?

들어가기에 앞서 로컬 저장소가 뭔지 헷갈린다면 이해하고 넘어가보자

로컬 저장소는 네트워크 서버가 아닌 디바이스에 데이터를 저장하는 공간을 의미한다
디바이스에 저장하기 때문에 네트워크 연결 여부와는 관계 없이 사용할 수 있다

 

✏️ SQLite

SQLite는 안드로이드에 내장된 데이터베이스로 구조화된 데이터를 저장할 때 사용한다
직접 SQL 쿼리를 작성해야하는 번거로움이 있다

현재는 Room을 자주 사용하지만 이전에는 SQLite가 기본 옵션이었다!

  • SQL 문법을 사용해 CRUD 작업을 수행
  • Cursor를 사용해 데이터를 직접 매핑해야 함
  • 데이터베이스의 스레드 관리를 개발자가 직접 해야 함
  • 유효성 검사 및 쿼리 검증이 런타임에서 이루어짐

 

🔹 SQLite 사용법

SQLite를 어떻게 사용하는지 간단한 코드를 통해 살펴보자

우선 SQLite를 사용하려면 SQLiteOpenHelper를 상속받아 데이터베이스를 관리해야한다

class DBHelper(context: Context) : SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) {
    override fun onCreate(db: SQLiteDatabase) {
        db.execSQL("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)")
    }

    override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
        db.execSQL("DROP TABLE IF EXISTS users")
        onCreate(db)
    }

    fun insertUser(name: String, age: Int) {
        val db = writableDatabase
        val values = ContentValues().apply {
            put("name", name)
            put("age", age)
        }
        db.insert("users", null, values)
    }

    fun getUser(id: Int): User? {
        val db = readableDatabase
        val cursor = db.rawQuery("SELECT * FROM users WHERE id = ?", arrayOf(id.toString()))
        return if (cursor.moveToFirst()) {
            val user = User(cursor.getInt(0), cursor.getString(1), cursor.getInt(2))
            cursor.close()
            user
        } else {
            cursor.close()
            null
        }
    }
}
  • onCreate: 테이블 생성 (앱이 최초 실행될 때 한번만 호출)
  • onUpgrade: DB 업그레이드 (마이그레이션)
  • insertUser: 데이터 삽입 예시
  • getUser: 특정 사용자 조회 예시

 

MainActivity에서의 사용:

val dbHelper = DBHelper(this)
dbHelper.insertUser("홍길동", 25)
val user = dbHelper.getUser(1)
Log.d("DB", "User: ${user?.name}, Age: ${user?.age}")

 

SQLite는 직접적인 SQL 작성과 수동 데이터 매핑으로 인해 코드가 복잡하고 유지보수가 어렵다

이런 문제를 해결하기 위해 Room이 등장하였다



✏️ Room

Room은 SQLite를 추상화한 Jetpack 라이브러리로 직접 SQL을 작성하지 않고도 데이터베이스를 다룰 수 있게 한다

  • 자동 객체 매핑: 쿼리 결과를 지정한 데이터 클래스로 자동 매핑
  • SQL 작성 간소화: @Query 어노테이션을 사용해 간단히 쿼리를 정의 가능
  • 스레드 관리: 백그라운드 스레드에서 데이터 작업을 자동으로 처리하여 메인 스레드를 차단하지 않음
  • 유효성 검사: 컴파일 타임에 SQL 문법과 데이터베이스 스키마를 검증하여 런타임 오류를 방지
  • LiveData 및 Flow 지원: 데이터 변경 사항을 실시간으로 감지하여 UI에 반영 가능
  • 마이그레이션 지원: 데이터베이스 구조 변경 시, 간단한 API로 마이그레이션을 처리

 

🔸 Room 사용법 (Entity, Dao, Database)

Room을 사용하려면 Entity, Dao, Database를 정의해야 한다

1️⃣ Entity

데이터베이스 테이블을 정의하는 데이터 클래스

@Entity(tableName = "users")
data class User(
    @PrimaryKey val id: Int,
    val name: String,
    val age: Int
)

 

2️⃣ Dao (Data Access Object)

쿼리를 추상화한 인터페이스 CRUD 연산 수행
쿼리문을 어노테이션으로 정의하고 Room이 구현한다

@Dao
interface UserDao {
    @Insert
    fun insertUser(user: User)

    @Query("SELECT * FROM users WHERE id = :userId")
    fun getUser(userId: Int): User
}

 

3️⃣ Databse

데이터베이스의 진입점(Access Point)으로 RoomDatabase를 상속받아 정의한다

@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
    abstract fun userDao(): UserDao
}

 

MainActivity에서의 사용:

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

val userDao = db.userDao()
userDao.insertUser(User(name = "홍길동", age = 25))
val user = userDao.getUser(1)
Log.d("DB", "User: ${user?.name}, Age: ${user?.age}")



✏️ Room과 SQLite의 차이점

기능 SQLite Room
쿼리 작성 직접 SQL 작성 필요 @Query 어노테이션으로 간결한 정의 가능
데이터 매핑 Cursor를 사용해 수동 매핑 필요 자동 객체 매핑 지원
스레드 관리 별도 스레드 관리 필요 자동 백그라운드 스레드 지원
유효성 검사 실행 중 오류 발생 가능 컴파일 타임에 SQL 문법 및 엔터티 검증
라이브 데이터 연동 기본적으로 불가능 LiveData, Flow, RxJava와 통합 지원
마이그레이션 수동 처리 필요 간단한 마이그레이션 API 제공

위의 표를 토대로 SQLite보다 Room을 추천하는 이유를 정리해보았다:

  1. 추상화와 편의성: Room은 SQL 문법을 몰라도 쉽게 사용할 수 있다
  2. 안전성: Room은 컴파일 타임에 SQL 문법과 스키마를 검증해 런타임 오류를 줄인다
  3. 생산성: Room은 DAO와 객체 매핑을 제공해 생산성을 높이고, SQLite는 수동 처리로 인해 복잡하다
  4. 실시간 데이터 연동: Room은 LiveData, Flow와 같은 현대적인 데이터 흐름 지원한다



✅ 마무리

SQLite는 직접 SQL을 작성해야 하므로 번거롭지만
Room은 이를 추상화하여 더욱 편리하게 사용할 수 있도록 지원한다

따라서! Room을 사용하는 것을 권장한다!



📌 참고 자료

  • Android 공식 문서: SQLite
  • Android 공식 문서: Room

'Android > Study' 카테고리의 다른 글

[Android/Kotlin] RecyclerView에 ItemDecoration으로 구분선 넣기  (2) 2025.02.06
[Android] RecyclerView와 ViewHolder 패턴 (+ListVIew)  (4) 2025.02.05
[Jetpack Compose] Android Navigation 기초  (2) 2025.01.23
[Jetpack Compose] Scaffold 사용법  (1) 2025.01.21
[Jetpack Compose] 위치 권한 요청 및 처리하기  (1) 2025.01.15
'Android/Study' 카테고리의 다른 글
  • [Android/Kotlin] RecyclerView에 ItemDecoration으로 구분선 넣기
  • [Android] RecyclerView와 ViewHolder 패턴 (+ListVIew)
  • [Jetpack Compose] Android Navigation 기초
  • [Jetpack Compose] Scaffold 사용법
romieeeee
romieeeee
  • romieeeee
    progromi
    romieeeee
  • 전체
    오늘
    어제
  • 글쓰기 관리
    • 분류 전체보기 (16)
      • Kotlin (2)
      • Android (1)
        • Study (11)
        • Error (2)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    logcat 문제해결
    lazyinit
    bottombar
    jetpack compose
    lazyinit var
    horizontalpager
    위치 권한
    lazythreadsafetymode
    suggestionchip
    AndroidStudio
    mutablestateof
    주소api
    compose
    assistchip
    Android
    SGIS
    Kotlin
    RecyclerView
    navcontroller
    flowrow
    inputchip
    kotlin val
    filterchip
    logcat 한글 깨짐
    shouldshowrequestpermissionrationale
    requestpermissionlauncher
    ondrawover
    pagerstate
    divideritemdecoration
    NavHost
  • 최근 댓글

  • hELLO· Designed By정상우.v4.10.3
romieeeee
[Android] SQLite vs Room
상단으로

티스토리툴바