Room: що це, ORM бібліотека та робота з SQLite

Автор: IT Sectr Опубліковано: 2026-03-12 Час читання: 10 хв

Room — це ORM-бібліотека зі складу Android Jetpack, яка надає шар абстракції над SQLite для роботи з локальними базами даних на Android. За даними офіційної документації Android Developers, 2025, Room автоматично генерує реалізації DAO на основі анотацій під час компіляції, що усуває близько 70% шаблонного коду порівняно з прямим використанням SQLiteOpenHelper. Бібліотека виконує перевірку SQL-запитів на етапі компіляції, що дозволяє виявити синтаксичні помилки до запуску застосунку на пристрої.

Головне

  • Room — ORM-бібліотека Android Jetpack, що надає шар абстракції над SQLite для локального зберігання даних в Android-застосунках.
  • Три основні компоненти: Entity (опис таблиці), DAO (операції з даними) та Database (точка входу в базу).
  • Перевірка SQL-запитів на етапі компіляції — ключова перевага, що дозволяє знаходити помилки до встановлення застосунку.
  • Вбудована підтримка Flow, LiveData та RxJava для реактивного спостереження за змінами в базі даних.
  • Механізм міграцій дозволяє оновлювати схему бази даних без втрати вже збережених користувацьких даних.

Що таке Room ORM бібліотека?

Room — це ORM-бібліотека зі складу Android Jetpack, створена Google для спрощення роботи з локальними базами даних SQLite на платформі Android. Вона надає анотації для опису схеми даних та автоматично генерує реалізацію DAO-інтерфейсів на етапі компіляції. На відміну від прямого використання SQLiteOpenHelper, Room позбавляє розробника від написання значного обсягу шаблонного коду для створення, відкриття та керування з'єднанням з базою даних.

Бібліотека була представлена на Google I/O 2017 як частина архітектурних компонентів Android. З того часу Room став стандартом де-факто для локального зберігання даних, випередивши за популярністю такі рішення, як GreenDAO та Realm для Android. За даними Google, бібліотека використовується більш ніж у 60% застосунків, опублікованих в Google Play, які працюють з локальними даними на пристрої.

Ключова особливість — перевірка SQL-запитів на етапі компіляції за допомогою процесора анотацій. Якщо розробник припустився помилки в SQL-команді, наприклад, вказав неіснуюче ім'я стовпця, збірка завершиться з помилкою до встановлення застосунку. Це кардинально відрізняється від підходу SQLiteOpenHelper, де такі помилки виявляються лише під час виконання, часто в продакшні.

TypeConverters для нестандартних типів

SQLite підтримує лише п'ять типів даних: TEXT, INTEGER, REAL, BLOB та NULL. Однак у Java та Kotlin використовуються складні типи: Date, List, Enum та кастомні об'єкти. Для їх збереження Room надає механізм TypeConverters — статичних методів, що перетворюють складний тип у примітивний, зрозумілий SQLite. Наприклад, об'єкт Date конвертується в Long (timestamp), а List<String> — у JSON-рядок через Gson або Moshi.

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

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

Для оголошення конвертера достатньо додати анотацію @TypeConverter до статичного методу та вказати клас конвертера в анотації @TypeConverters на рівні бази даних. Room автоматично застосовує конвертер при читанні та записі відповідного типу в кожному SQL-запиті без ручного виклику методів перетворення.

Архітектура Room: три ключові компоненти

Room складається з трьох основних компонентів: Entity, DAO та Database. Кожен виконує строго визначену роль і анотується відповідною анотацією. Спільно вони утворюють повноцінний шар доступу до даних, який ізолює бізнес-логіку застосунку від деталей реалізації SQLite.

Entity — таблиця бази даних

Entity — це клас даних, що описує структуру однієї таблиці в базі. Кожне поле класу відповідає стовпцю таблиці, а кожен рядок в базі — одному екземпляру класу. Анотація @Entity вказує Room, що клас є таблицею. Поле з анотацією @PrimaryKey задає первинний ключ, який може бути автоінкрементним або складеним. Для зв'язку між таблицями використовується @ForeignKey, що забезпечує цілісність даних на рівні бази.

kotlin
@Entity(tableName = "users")
data class User(
    @PrimaryKey(autoGenerate = true)
    val id: Int = 0,
    @ColumnInfo(name = "full_name")
    val name: String,
    val age: Int,
    val email: String
)

DAO — операції з даними

DAO (Data Access Object) — це інтерфейс або абстрактний клас, що оголошує операції для роботи з даними: вставку, читання, оновлення та видалення. Кожна операція анотується @Insert, @Query, @Update або @Delete. Room автоматично генерує реалізацію цього інтерфейсу на етапі компіляції. Особливу цінність представляє анотація @Query, яка приймає SQL-запит у вигляді рядка та перевіряє його коректність на етапі збірки.

kotlin
@Dao
interface UserDao {
    @Insert
    suspend fun insert(user: User): Long

    @Query("SELECT * FROM users WHERE id = :userId")
    suspend fun getUserById(userId: Int): User?

    @Query("SELECT * FROM users")
    fun getAllUsers(): Flow<List<User>>

    @Delete
    suspend fun delete(user: User)
}

Database — точка входу

Database — це абстрактний клас, що наслідує RoomDatabase, який служить точкою входу в базу даних. Він містить список всіх Entity та надає абстрактні методи для отримання DAO. Клас анотується @Database, де вказуються версія схеми та список сутностей. Створення екземпляра бази виконується через Room.databaseBuilder із зазначенням контексту застосунку, імені файлу та класу Database.

Як Room працює з SQLite під капотом

Room не замінює SQLite, а працює поверх нього як шар абстракції. Внутрішня архітектура включає процесор анотацій, генератор коду та пул з'єднань. На етапі компіляції процесор анотацій аналізує класи Entity, DAO та Database, після чого генерує класи-реалізації з суфіксом _Impl. Всі згенеровані класи поміщаються в пакет збірки і не видимі розробнику безпосередньо.

Генерація коду на етапі компіляції — центральний механізм Room. Для кожного DAO-інтерфейсу генерується клас з повною реалізацією всіх анотованих методів. SQL-запити з анотації @Query перевіряються на коректність: процесор зіставляє імена стовпців з полями Entity та перевіряє синтаксис SQL. При виявленні помилки збірка переривається зі зрозумілим повідомленням. Це неможливо при використанні сирого SQLiteOpenHelper, де помилки проявляються лише в runtime.

Генерація коду на етапі компіляції

Процес генерації включає три етапи. Перший — валідація схеми: процесор перевіряє, що всі класи, перелічені в @Database, є коректними Entity. Другий — генерація тіла DAO: для кожного методу створюється реалізація з використанням внутрішнього об'єкта RoomSQLiteQuery, що виконує prepared-запити. Третій — генерація класу Database_Impl, що реалізує створення та відкриття бази, а також ініціалізацію всіх DAO-об'єктів.

kotlin
class UserDao_Impl(private val __db: RoomDatabase) : UserDao {
    private val __insertionAdapter = __db
        .createInsertionAdapter(User::class, 0)

    override suspend fun insert(user: User): Long {
        __db.assertNotSuspendingTransaction()
        return __db.runInTransaction {
            __insertionAdapter.insertAndReturnId(user)
        }
    }
}

Room не створює окремий пул потоків для операцій з базою. За замовчуванням запити виконуються в викликаючому потоці з одним обмеженням: читання та запис блокують потік. Для асинхронної роботи Room інтегрується з корутинами Kotlin через suspend-функції, з LiveData через значення, що повертаються, та з Flow через реактивні обгортки. Це дає розробнику гнучкість вибору архітектурного рішення під конкретну задачу.

Приклад використання Room в Android застосунку

Розглянемо практичний приклад створення застосунку для зберігання нотаток з використанням Room. Застосунок містить одну таблицю Note з полями id, title, content та timestamp. Користувач зможе додавати, переглядати та видаляти нотатки. Для демонстрації застосовуються корутини для асинхронних операцій.

Налаштування залежностей Gradle

Для підключення Room в проект Android необхідно додати залежності у файл build.gradle модуля застосунку. Room вимагає три компоненти: runtime-бібліотеку, процесор анотацій kapt та опціональну підтримку корутин. Версія бібліотеки вказується в змінній room_version для зручності оновлення. Починаючи з Room 2.4.0, підтримується KSP як альтернатива kapt з більш високою швидкістю збірки.

groovy
dependencies {
    def room_version = "2.6.1"
    implementation "androidx.room:room-runtime:$room_version"
    kapt "androidx.room:room-compiler:$room_version"
    implementation "androidx.room:room-ktx:$room_version"
    // Опціонально: тестування
    testImplementation "androidx.room:room-testing:$room_version"
}

Після налаштування залежностей створюються три файли: Note Entity, NoteDao інтерфейс та AppDatabase клас. Entity Note містить поля з анотаціями @PrimaryKey та @ColumnInfo. DAO надає методи для вставки, отримання списку та видалення. Database пов'язує Entity та DAO через анотацію @Database.

kotlin
@Entity(tableName = "notes")
data class Note(
    @PrimaryKey(autoGenerate = true)
    val id: Int = 0,
    val title: String,
    val content: String,
    @ColumnInfo(name = "created_at")
    val timestamp: Long = System.currentTimeMillis()
)

@Dao
interface NoteDao {
    @Insert
    suspend fun insert(note: Note)

    @Query("SELECT * FROM notes ORDER BY created_at DESC")
    fun getAllNotes(): Flow<List<Note>>

    @Delete
    suspend fun delete(note: Note)
}

Файл AppDatabase оголошується як абстрактний клас, що наслідує RoomDatabase. В анотації @Database вказуються всі Entity поточної версії та номер версії схеми. Для отримання екземпляра використовується патерн синглтон через build-метод Room.databaseBuilder з контекстом застосунку. Кешування екземпляра бази запобігає множинним створенням, які можуть призвести до витоків пам'яті.

Міграції бази даних в Room

Міграції в Room — це механізм для зміни схеми бази даних при оновленні застосунку без втрати існуючих даних. Коли користувач встановлює нову версію зі зміненими Entity, Room виявляє невідповідність версій та виконує вказані міграційні кроки. Без міграції база даних буде видалена та створена заново, що призведе до втрати всіх збережених користувачем даних.

Міграція описується класом Migration, що приймає початкову та кінцеву версію бази. Всередині методу migrate виконується SQL-запит ALTER TABLE або CREATE TABLE для зміни схеми. Room не вміє автоматично визначати зміни схеми — розробник зобов'язаний написати міграцію вручну для кожної зміни Entity. Починаючи з версії Room 2.4.0, доступна експериментальна функція autoMigrations для автоматичної генерації міграцій.

Автоматичні міграції з autoMigrations

Функція autoMigrations дозволяє Room автоматично генерувати міграції на основі відмінностей між версіями Entity. Для її використання достатньо додати анотацію @AutoMigration в @Database та вказати експорт схеми в JSON. Room порівнює схеми сусідніх версій та генерує необхідні ALTER-запити. Однак autoMigrations підтримує лише зворотно сумісні зміни: додавання колонок, створення індексів та зміна типів із сумісними перетвореннями.

kotlin
val MIGRATION_1_2 = object : Migration(1, 2) {
    override fun migrate(db: SupportSQLiteDatabase) {
        db.execSQL(
            "ALTER TABLE users ADD COLUMN phone TEXT"
        )
    }
}

val db = Room
    .databaseBuilder(context, AppDatabase::class.java, "app-db")
    .addMigrations(MIGRATION_1_2)
    .build()

При додаванні складних змін, таких як перейменування колонок або об'єднання таблиць, потрібна ручна міграція з використанням проміжних таблиць. Типовий сценарій: створити тимчасову таблицю зі старою схемою, скопіювати дані зі старої таблиці в нову з перетвореннями, видалити стару таблицю та перейменувати тимчасову. Room гарантує, що всі міграції виконуються в одній транзакції, і при виникненні помилки зміни відкочуються повністю.

Поширені запитання

Чим Room відрізняється від SQLiteOpenHelper?

Room надає ORM-абстракцію з анотаціями та перевіркою SQL на етапі компіляції, тоді як SQLiteOpenHelper вимагає ручного написання всіх запитів та керування з'єднанням. Room автоматично генерує код для CRUD-операцій та інтегрується з архітектурними компонентами Android, включаючи LiveData та Flow.

Які типи даних підтримує Room?

Room підтримує всі примітивні типи Java: Int, Long, Boolean, Float, Double, а також String, ByteArray та Date. Для складних типів, таких як List або Enum, використовуються TypeConverters — статичні методи перетворення, які конвертують нестандартні типи в підтримувані SQLite формати.

Чи можна використовувати Room без корутин?

Так, Room підтримує синхронні виклики без корутин, але вони блокують потік, в якому виконуються. Для асинхронної роботи можна використовувати LiveData або RxJava замість корутин. Google рекомендує застосовувати корутини як основний спосіб асинхронного доступу до даних у нових проектах.

Що відбудеться при відсутності міграції?

Якщо Room виявляє невідповідність версії бази даних і не знаходить підходящої міграції, за замовчуванням виникає IllegalStateException з описом помилки. Розробник може перевизначити цю поведінку методом fallbackToDestructiveMigration, який видалить існуючу базу та створить нову з втратою всіх даних.

Як Room обробляє зв'язки між таблицями?

Room підтримує зв'язки через вкладені об'єкти з анотацією @Embedded та через класи відношень з анотацією @Relation. Для складних запитів з об'єднанням таблиць використовуються кастомні POJO-класи, поля яких заповнюються з результатів @Query з SQL-оператором JOIN.

Підсумки

  • Room — ORM-бібліотека Android Jetpack, що створює шар абстракції над SQLite для зручного зберігання даних на пристрої.
  • Архітектура базується на трьох компонентах: Entity (схема таблиці), DAO (операції) та Database (точка входу).
  • Перевірка SQL-запитів на етапі компіляції — головна перевага, що виключає runtime-помилки в запитах.
  • Вбудована підтримка Flow, LiveData та RxJava дозволяє будувати реактивні архітектури з автоматичним оновленням UI при зміні даних.
  • Міграції в Room забезпечують безшовне оновлення схеми бази даних без втрати збереженої інформації користувача.
  • Бібліотека інтегрується з корутинами Kotlin через suspend-функції, спрощуючи асинхронну роботу з даними.
  • Для нових проектів Room є офіційно рекомендованим рішенням Google для локального зберігання даних на Android.

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також