app 수준 그래이들에서 의존성 추가
plugins {
id("org.jetbrains.kotlin.kapt")
}
// Room Persistence Library
implementation("androidx.room:room-runtime:2.6.1")
kapt("androidx.room:room-compiler:2.6.1") // Kotlin 사용 시
// annotationProcessor("androidx.room:room-compiler:2.6.1") // Java 사용 시
// Kotlin Coroutines (Room과 함께 사용하면 편리)
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.0")
// 선택 사항: LiveData 지원
implementation("androidx.room:room-ktx:2.6.1")
@Entity(tableName = "terms-table")
data class TermsModel(
@PrimaryKey(autoGenerate = true)
val id : Int = 0,
val title : String,
val content : String,
){
// 보조 생성자를 사용하여 id 없이 객체 생성 가능
constructor(title: String, content: String) : this(0, title, content)
}
- @Entity(tableName = "users"): 이 클래스가 users라는 이름의 데이터베이스 테이블에 매핑될 엔티티임을 나타냅니다. 테이블 이름을 지정하지 않으면 클래스 이름이 기본 테이블 이름으로 사용
- @PrimaryKey(autoGenerate = true): id 필드가 기본 키이며, 데이터베이스에서 자동으로 값을 생성하도록 지정
- @ColumnInfo(name = "first_name"): firstName 필드의 데이터베이스 컬럼 이름을 first_name으로 지정합니다. 컬럼 이름을 지정하지 않으면 필드 이름이 기본 컬럼 이름으로 사용
@Dao
interface TermsDao {
@Insert
suspend fun insertTerms(termsModel: TermsModel)
@Query("SELECT * FROM 'terms-table'")
fun selectAllTerms():Flow<List<TermsModel>>
@Query("SELECT * FROM 'terms-table' WHERE id = :id")
fun selectByTermsId(id:Int):Flow<TermsModel>
@Query("DELETE FROM 'terms-table'")
suspend fun clearTable()
}
- @Dao: 이 인터페이스가 DAO임을 나타내는 어노테이션
- 콜론(:) 뒤에 오는 이름은 메서드 파라미터와 매핑됨
- @Insert(onConflict = OnConflictStrategy.IGNORE): 삽입 충돌이 발생했을 때 기존 데이터를 무시하도록 설정, 다른 전략으로는 REPLACE (기존 데이터 덮어쓰기), ABORT (작업 중단) 등이 있다
- suspend 키워드는 이 함수가 코루틴 내에서 호출되어야 함을 나타냄
@Database(entities = [TermsModel::class], version = 1)
abstract class TermsDB : RoomDatabase(){
abstract fun termsDao() : TermsDao
companion object {
@Volatile
private var INSTANCE:TermsDB?=null
fun getInstance(context: Context):TermsDB{
synchronized(this) {
var instance = INSTANCE
if (instance==null) {
instance = Room.databaseBuilder(
context.applicationContext,
TermsDB::class.java,
"terms_DB"
).fallbackToDestructiveMigration().build()
INSTANCE = instance
}
return instance
}
}
}
}
- @Database(entities = [User::class], version = 1, exportSchema = false):
-> entities = [User::class]: 이 데이터베이스가 관리할 엔티티 목록을 지정, 여러 개의 엔티티가 있다면 쉼표로 구분하여 나열
-> version = 1: 데이터베이스 스키마의 버전을 나타냅니다. 데이터베이스 구조가 변경될 때마다 이 버전을 증가시켜 Room이 마이그레이션을 처리
-> exportSchema = false: 스키마 내보내기 기능을 비활성화합니다. 프로덕션 환경에서는 스키마를 내보내어 버전 관리에 활용- abstract fun termsDao(): TermsDao : TermsDao 인터페이스의 인스턴스를 반환하는 추상 메서드를 정의. Room은 이 메서드의 구현체를 자동으로 제공함
- companion object: 데이터베이스 인스턴스를 싱글톤으로 관리하기 위한 동반 객체
- @Volatile private var INSTANCE: AppDatabase? = null: 앱 전체에서 공유할 데이터베이스 인스턴스를 저장하는 변수. @Volatile은 여러 스레드에서 안전하게 접근할 수 있도록 보장
- fun getDatabase(context: Context): AppDatabase: 데이터베이스 인스턴스를 가져오는 팩토리 메서드. 싱글톤 패턴을 구현하여 앱 내에서 하나의 데이터베이스 인스턴스만 사용함
- Room.databaseBuilder(...): Room의 databaseBuilder를 사용하여 데이터베이스 인스턴스를 생성
- .fallbackToDestructiveMigration(): 마이그레이션 전략이 없을 때 데이터베이스를 삭제하고 새로 생성하는 옵션. 개발 단계에서는 편리하지만, 실제 앱에서는 데이터 손실을 유발할 수 있으므로 주의
class MainActivity : AppCompatActivity() {
private lateinit var userDao: UserDao
private lateinit var db: AppDatabase
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
db = AppDatabase.getDatabase(applicationContext)
userDao = db.userDao()
// 데이터 삽입
lifecycleScope.launch {
val newUser = User(firstName = "John", lastName = "Doe", age = 30)
userDao.insert(newUser)
Log.d("Room", "User inserted with ID: ${newUser.id}")
}
// 데이터 조회
lifecycleScope.launch {
val users = userDao.getAll()
Log.d("Room", "All users: $users")
val userById = userDao.getUserById(1)
Log.d("Room", "User with ID 1: $userById")
}
// 데이터 업데이트
lifecycleScope.launch {
val existingUser = userDao.getUserById(1)
existingUser?.let {
val updatedUser = it.copy(age = 31)
userDao.update(updatedUser)
Log.d("Room", "User updated: $updatedUser")
}
}
// 데이터 삭제
lifecycleScope.launch {
val userToDelete = userDao.getUserById(1)
userToDelete?.let {
userDao.delete(it)
Log.d("Room", "User deleted: $it")
}
}
// Flow를 이용한 데이터 관찰
lifecycleScope.launch {
userDao.getUsersByAgeDescending().collect { users ->
Log.d("Room", "Users sorted by age (descending): $users")
// UI 업데이트 등 수행
}
}
}
}