DB + SQL

Android에서 로컬 데이터베이스 접근하기

dev_SiWoo 2025. 10. 24. 18:08

Android에서 sqlite3와 같은 로컬 DB를 사용해야하는 상황을 직면했다.

 

이 때, 보통 Spring에서 사용하는 Mybatis와 같은 서버측 ORM 프레임워크와  비슷하게 DB에 접근하여 ORM 역할을 학는 공식 라이브러리 중 최신 표준이라고 하는 Room Persistence Library가 존재하였다.

 

 

Room Persistence Library는 현재 안드로이드 앱 개발에서 가장 권장되는 방법이자, MyBatis와 같은 ORM의 역할을 대신하는 공식 라이브러리라고한다.

 

 

SQLite 위에 추상화 계층을 제공하여 SQL쿼리를 컴파일 시점에 검사하고, 복잡한 보일러 플레이코드를 줄여준다고한다.

 

1. Entity(테이블 정의)

// InspectionItem.kt
import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity(tableName = "inspection_items") // 💡 테이블 이름 지정
data class InspectionItem(
    // 💡 Primary Key 지정 및 Auto-generation 설정 (필요에 따라)
    @PrimaryKey(autoGenerate = true)
    val itemId: Int = 0,
    
    // 테이블의 컬럼들
    val name: String,
    val status: String,
    val inspectorId: Int
)

 

2. DAO (Data Access Object)

// InspectionItemDao.kt
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Update
import androidx.room.Delete
import kotlinx.coroutines.flow.Flow

@Dao
interface InspectionItemDao {
    
    // 💡 모든 항목을 조회하는 쿼리
    @Query("SELECT * FROM inspection_items ORDER BY itemId DESC")
    fun getAllItems(): Flow<List<InspectionItem>> // Flow는 실시간 업데이트를 지원

    // 💡 특정 검사원의 항목만 조회하는 쿼리
    @Query("SELECT * FROM inspection_items WHERE inspectorId = :id")
    suspend fun getItemsByInspector(id: Int): List<InspectionItem>

    // 💡 새 항목을 삽입하는 메서드
    @Insert
    suspend fun insert(item: InspectionItem)

    // 💡 항목을 업데이트하는 메서드
    @Update
    suspend fun update(item: InspectionItem)

    // 💡 항목을 삭제하는 메서드
    @Delete
    suspend fun delete(item: InspectionItem)
    
    // 💡 모든 데이터를 삭제하는 쿼리 (동기화 시 유용)
    @Query("DELETE FROM inspection_items")
    suspend fun deleteAll()
}

 

3. Database (DB 생성 및 버전 관리)

// AppDatabase.kt
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase

// 💡 데이터베이스에 포함될 모든 Entity와 버전을 지정
@Database(entities = [InspectionItem::class], version = 1, exportSchema = false)
abstract class AppDatabase : RoomDatabase() {

    // 💡 DAO에 접근할 수 있는 추상 메서드
    abstract fun itemDao(): InspectionItemDao

    // 싱글톤 패턴을 위한 Companion Object
    companion object {
        @Volatile
        private var INSTANCE: AppDatabase? = null

        fun getDatabase(context: Context): AppDatabase {
            // INSTANCE가 null이 아닐 경우, 반환
            // null일 경우, 데이터베이스를 생성 (synchronized로 스레드 안전성 확보)
            return INSTANCE ?: synchronized(this) {
                val instance = Room.databaseBuilder(
                    context.applicationContext,
                    AppDatabase::class.java,
                    "inspection_db" // 💡 SQLite 파일 이름
                ).build()
                INSTANCE = instance
                instance
            }
        }
    }
}