Google에서 제공하는 ORM(Object-relational mapping)
SQLite에 대한 추상화 레이어를 제공하여 원활한 데이터베이스 액세스를 지원하며 SQLite를 완벽히 활용함
실행 기기에 앱 데이터 캐시를 만들고 네트워크 연결 여부와 관계없이 사용자가 콘텐츠를 탐색할 수 있음
ORM - Object Relational Mapping, 객체-관계 매핑
- 객체 지향 프로그래밍은 클래스를 사용하고 관계성 데이터 베이스에서는 테이블을 사용하기 때문에 객체 모델과 관계형 모델 간에 불일치가 발생함
- ORM은 객체 간의 관계를 바탕으로 SQL을 자동으로 생성하여 불일치를 해결함
- 즉, 객체를 통해 간접적으로 데이터 베이스의 데이터를 다룸
- Persistant API라고도 할 수 있음
Persistence(영속성)
데이터를 생성한 프로그램이 종료되더라도 사라지지 않는 데이터의 특성
→ 영속성을 가지지 않는 데이터는 프로그램 종료 시 소멸
SQLite보다 Room을 사용해야 하는 이유
- 컴파일 타임에 SQL에 대한 유효성 검사가 가능하다.
- Schema 변경 시, 자동으로 업데이트가 가능하다.
- boilerplate code 없이 ORM 라이브러리를 통해서 Java나 Kotlin 객체에 매핑할 수 있다.
- Observation을 위한 LiveData 등과 함께 작동하도록 구축되었다.
Room의 3가지 요소
Room Database
- 기본 SQLite 데이터베이스에 대한 엑세스 포인트 역할
- 데이터베이스 작업 단순화
- RoomDatabase를 확장하는 추상 클래스로 사용하며 보통 싱글톤 패턴으로 정의함
Annotation
@Database : 해당 클래스가 Database 임을 알려주는 어노테이션
- entites : 해당 Database에 어떤 테이블이 있는지 명시하는 속성
- version : Scheme가 바뀔 때 해당 속성을 변경해야 함
- exportSchema : Room의 Schema 구조를 폴더로 export할 것인가에 대한 속성
DAO (Data Access Objects)
- 데이터베이스에 엑세스하는데 사용되는 메서드를 정의하는 클래스
- 사용자가 DAO의 함수를 호출하면 Room Database에서 해당 함수의 작업을 실행
Annotation
@Insert : 삽입 - @Entity로 정의된 클래스 객체, 해당 클래스의 collection, array만 인자로 받을 수 있음 @Update : 업데이트 - return 값으로 업데이트된 행의 개수를 반환 받을 수 있음
@Delete : 삭제 - return 값으로 삭제된 행의 개수를 반환 받을 수 있음
@Query : 쿼리 - 쿼리문을 작성하여 실행할 수 있음
3. Entity
- 데이터베이스 내의 DB 테이블을 나타냄
Annotation
@Entity : 테이블 선언
- tableName : 테이블 명, 기본으로 클래스 명이 테이블 명이 됨
@ColumnInfo : 컬럼 선언
- name : 컬럼 명, 기본으로 argument 명이 column 명이 됨
@PrimaryKey : 테이블의 PK
- 앱은 Room DB를 사용하여 DB와 연결된 DAO를 가져옴
- 앱은 각 DAO를 통해 DB CRUD를 처리
- 앱은 Entity를 사용하여 DB 테이블 column에 해당하는 값을 가져오고 setting
주의사항
Room의 CRUD 처리는 메인 스레드(UI 스레드)가 아닌 Background Thread에서 처리해야 함
데이터를 받아올 때 처리시간이 길어질 경우 UI에 영향을 줄 수 있기 때문,
그러나 메인 스레드에서 DB에 대한 접근을 허용하고 싶다면 allowMainThreadQueries() 호출
기본 코드셋
Database
entities를 가지고 있고 (배열로 다수도 가능), RoomDatabase를 상속받으며, 인자가 없는 dao 추상 메서드를 가지고 있다.
@Database(entities = [Test::class], version = 1)
abstract class TestDatabase : RoomDatabase() {
abstract fun testDao() : TestDao
}
Entity
Database 안의 테이블을 표현
@Entity
data class Test(
//autoGenerate null을 받으면 ID 값을 자동으로 할당
@PrimaryKey(autoGenerate = true)
var id : Int?,
@ColumnInfo(name ="title")
var title: String,
@ColumnInfo(name="description")
var description: String,
@ColumnInfo(name="imageUrl")
var imageUrl: String
){
constructor() : this(null,"","","")
}
DAO
database를 어떻게 사용할 것인지에 대한 Method 들을 포함
@Dao
interface TestDao {
@Query("SELECT * FROM Test")
fun getAll(): LiveData<List<Test>>
@Insert(onConflict = OnConflictStrategy.REPLACE) // 중복 ID일 경우 교체
fun insert(todo: Test)
@Update
fun update(todo: Test)
@Delete
fun delete(todo: Test)
}
실제 사용
@Database(entities = [Test::class], version = 1)
abstract class TestDatabase : RoomDatabase() {
abstract fun testDao() : TestDao
//싱글톤 패턴
companion object{
private var Instance : TestDatabase? = null
fun getInstance(context:Context): TestDatabase? {
if (Instance == null) {
synchronized(TestDatabase::class) { //synchronized: 여러 스레드가 동시에 접근 불가. 동기적으로 접근
Instance = Room.databaseBuilder(
context.applicationContext,
TestDatabase::class.java, "test")
.fallbackToDestructiveMigration()
.build()
}
}
return Instance
}
}
}
DB 객체를 생성해주고 사용 의도에 따라 Dao에 접근해서 원하는 쿼리로 이루어진 함수를 호출하면 된다.
class TestRepository(application: Application) {
private val testDatabase: TestDatabase = TestDatabase.getInstance(application)!!
private val testDao: TestDao = testDatabase.testDao()
private val tests: LiveData<List<Test>> = testDao.getAll()
fun getAll(): LiveData<List<Test>> {
return tests
}
fun insert(todo: Test){
testDao.insert(todo)
}
fun delete(todo: Test){
testDao.delete(todo)
}
fun update(todo: Test){
testDao.update(todo)
}
}
그리고 이러한 작업(DB에 접근해서 데이터를 가져오는 행위) 들을 수행하기 위해서는 백그라운드 Thread에서 처리해야 하기 때문에 Coroutine을 사용하거나 간단하게 Thread에 Runnable을 넣어서 처리해주면 된다.
Room
https://medium.com/@sunminlee89/room으로-sqlite를-쉽게-사용하자-5f0b9236009a
'Android > Library' 카테고리의 다른 글
GeoCoding 위도 경도 <-> 주소 변환하기 (4) | 2022.02.20 |
---|---|
Google Map API 사용 방법 및 예제 (0) | 2022.02.18 |
Epoxy, Epoxy에 Databinding 사용 (RecyclerView 쉽게 사용) (0) | 2022.02.14 |
Navigation (네비게이션) / Jetpack (0) | 2021.08.30 |
Hilt로 의존성 주입 (DI/Dependency Injection) (0) | 2021.08.30 |