Room
- Room이란?
- Android JetPack 라이브러리의 AAC(Android Architecture Component) 중 하나
- SQLite를 활용해서 기기 자체의 내부 저장소(로컬 데이터베이스)에 접근하는 방식
- 기기가 네트워크에 엑세스할 수 없는 오프라인 상태에서도 콘텐츠를 탐색할 수 있으며 다시 기기가 온라인 상태가 되면 변경사항이 DB에 동기화
- SQLite 대신 Room의 사용을 권장하는 이유
- SQL 쿼리의 컴파일 시간 확인 가능
- 반복적이고 오류가 발생하기 쉬운 상용구 코드를 최소화하는 편의 주석
- 간소화된 데이터베이스 이전 경로
- 👉 Room 데이터베이스 구현 관련 포스팅 참고
- 프로젝트 수준 build.gradle에 다음 코드 추가
👉 KSP 플러그인 추가 공식 문서(버전 참고)
id("com.google.devtools.ksp") version "1.9.22-1.0.17" apply false
- 모듈 수준 build.gradle의 plugin에 다음 코드 추가
id("com.google.devtools.ksp")
- 모듈 수준 build.gradle에 다음 중 필요한 의존성 추가
👉 Room 의존성 추가 공식 문서(버전 참고)
dependencies {
val room_version = "2.6.1"
implementation("androidx.room:room-runtime:$room_version")
annotationProcessor("androidx.room:room-compiler:$room_version")
ksp("androidx.room:room-compiler:$room_version")
implementation("androidx.room:room-ktx:$room_version")
implementation("androidx.room:room-guava:$room_version")
testImplementation("androidx.room:room-testing:$room_version")
implementation("androidx.room:room-paging:$room_version")
}
- data class 생성해 다음 Entity 코드 작성
- Entity
- 데이터베이스 테이블 정보를 클래스로 표현한 것
- @ColumnInfo: 테이블의 칼럼으로 설정할 변수 선언 시 명시할 어노테이션
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "UserInfo")
data class UserEntity(
@PrimaryKey(autoGenerate = true)
val id: Long = 0L,
@ColumnInfo(name = "name")
val name: String,
@ColumnInfo(name = "email")
val email: String,
@ColumnInfo(name = "password")
val password: String
)
- Interface 생성해 다음 DAO 코드 작성
- DAO
- 데이터베이스에 직접 접근하지 않고 DAO 객체를 생성해 데이터로 무엇을 할지 정의
- 인터페이스 상단에 @Dao 어노테이션 명시(Dao 인터페이스에서 테이블에 접근할 CRUD 메소드(Create, Read, Update, Delete)를 @Insert, @Query, @Update, @Delete 어노테이션을 사용해 정의)
- @Query : SQL 질의문을 통해 데이터베이스에 접근
- @Insert : 데이터베이스에 추가
(onConflict 속성은 칼럼이 충돌할 경우 어떻게 처리할지에 관한 속성)
- @Update : 데이터베이스 내용 갱신
- @Delete : 데이터베이스 내용 삭제
- 회원 등록과 삭제는 시간이 걸리는 작업이므로 코루틴 안에서 비동기적으로 수행하기 위해 앞에 suspend를 붙여줌
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
@Dao
interface LoginDAO {
@Query("select * from UserInfo")
fun getEmailList(): List<UserEntity>
@Query("select password from userinfo where email = :email")
fun getPasswordByEmail(email: String): String
@Insert
suspend fun insertUser(userInfo: UserEntity)
@Delete
suspend fun deleteUser(userInfo: UserEntity)
}
- 추상 클래스 생성해 다음 Database 코드 작성
- RoomDatabase 객체는 생성하는데 비용이 많이 들기 때문에 중복으로 생성하지 않도록 싱글톤으로 설정
- @Volatile이란?
- Java 변수를 Main Memory에 저장하겠다는 것을 명시하는 것
- 매번 변수의 값을 Read, Write할 때마다 CPU Cache가 아닌 Main Memory에 저장하고 불러오기 때문에 변수 값 불일치 문제를 방지할 수 있음
- 서로 다른 유저(스레드)가 동시에 데이터베이스에 접근하는 것을 막기 위해 syschronized 속성을 사용해 동기화
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
@Database(
entities = [UserEntity::class],
version = 1,
exportSchema = false
)
abstract class UserDatabase : RoomDatabase() {
abstract fun getLoginDAO(): LoginDAO
companion object {
@Volatile
private var INSTANCE: UserDatabase? = null
private fun buildDatabase(context: Context): UserDatabase = Room.databaseBuilder(
context, UserDatabase::class.java, "db_user"
).build()
fun getInstance(context: Context): UserDatabase = INSTANCE ?: synchronized(this) {
INSTANCE ?: buildDatabase(context).also { INSTANCE = it }
}
}
}