Room: concepte cheie, Entity, DAO și lucrul cu baza de date

Autor: IT Sectr Publicat: 2026-05-04 Timp de citire: 8 min

Room este o bibliotecă pentru lucrul cu SQLite în Android, care face parte din Jetpack. Oferă un strat de abstractizare peste SQLite brut, automatizând crearea tabelelor, executarea interogărilor și conversia datelor în obiecte Kotlin și Java. Conform Android Developers, Room compilează interogările SQL în faza de construire, verificând corectitudinea sintaxei și a relațiilor dintre Entity și tabele.

Principalele puncte

  • Room — bibliotecă ORM Jetpack pentru lucrul cu SQLite în aplicațiile Android.
  • Entity — clasă adnotată cu @Entity, fiecare instanță corespunde unui rând în tabel.
  • DAO — Data Access Object cu metode adnotate pentru interogări SQL.
  • Database — clasă abstractă care moștenește RoomDatabase, conectând Entity și DAO.
  • Migrarea — mecanism de modificare sigură a schemei bazei de date fără pierderea datelor utilizatorului.

Ce este Room și de ce este necesar

Room — este o bibliotecă de persistență din Android Jetpack care oferă mapare obiect-relațională pentru SQLite. Room rezolvă trei probleme principale ale SQLite brut: scrierea unui volum mare de cod boilerplate pentru crearea tabelelor, lipsa verificării interogărilor SQL la compilare și conversia manuală a Cursor în obiecte.

Biblioteca folosește compilatorul de adnotări (kapt sau KSP), care generează implementarea claselor abstracte RoomDatabase și DAO în faza de construire. Acest lucru garantează că erorile de sintaxă în SQL și nepotrivirile de tip sunt detectate înainte de lansarea aplicației, nu în runtime după publicarea în Google Play.

Conform Google I/O 2023, Room este utilizat în 68% din aplicațiile Android care lucrează cu date locale. Este standardul de stocare a datelor pe dispozitiv, recomandat de Google pentru toate proiectele noi — în locul învechitelor SQLiteOpenHelper și ContentProvider.

Implementați Room în proiecte care necesită cache local al datelor de pe server, mod offline sau stocarea datelor structurate ale utilizatorului cu posibilitatea de interogări SQL complexe.

Room face parte din Android Jetpack și este recomandat oficial de Google pentru toate proiectele noi care lucrează cu date locale. Spre deosebire de Realm sau ObjectBox, Room folosește SQLite nativ, ceea ce garantează compatibilitatea cu orice instrumente terțe pentru lucrul cu baza de date — de la DB Browser la DataGrip. Dezvoltatorul poate deschide fișierul .db al aplicației și poate executa interogări SQL direct, simplificând depanarea și analiza datelor în procesul de dezvoltare.

Entity și adnotări în Room

Entity — este o clasă de date adnotată cu @Entity, pe care Room o transformă într-un tabel al bazei de date. Fiecare câmp al clasei devine o coloană a tabelului, iar fiecare instanță — un rând. Room folosește reflecția pentru accesul la câmpuri, de aceea este necesară adnotarea @PrimaryKey pentru un identificator obligatoriu.

Adnotări de bază

Adnotarea @Entity informează Room că clasa este un tabel. Parametrul tableName stabilește numele tabelului dacă diferă de numele clasei. @PrimaryKey definește cheia primară cu posibilitatea de auto-generare prin autoGenerate = true.

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

@ColumnInfo stabilește numele coloanei în tabel dacă diferă de numele câmpului Kotlin. @Ignore exclude câmpul din tabel — nu va fi salvat în baza de date. @ForeignKey descrie cheile externe pentru relații între tabele cu operații în cascadă la ștergere sau actualizare.

Room suportă obiecte imbricate prin adnotarea @Embedded. Câmpurile clasei imbricate sunt desfăcute în coloane ale tabelului părinte cu un prefix pentru evitarea conflictelor de nume. De exemplu, clasa Address cu câmpurile city și street, încorporată în User, va crea coloanele address_city și address_street în tabelul users, eliminând necesitatea creării de tabele separate pentru obiecte-valoare simple.

Tipuri de conversie

Room suportă doar tipuri primitive și învelișurile lor. Pentru stocarea listelor, Date sau a tipurilor personalizate se folosește @TypeConverter — metode statice de conversie între tipul personalizat și primitivul SQLite, de exemplu, între List și un șir JSON.

DAO și interogări SQL

DAO (Data Access Object) — este o interfață sau clasă abstractă adnotată cu @Dao, care conține metode de acces la date. Fiecare metodă este adnotată cu o operație SQL: @Insert, @Update, @Delete sau @Query cu o interogare SQL explicită.

@Query cu verificare la compilare

Adnotarea @Query primește un șir SQL care este verificat de Room la compilare pentru corectitudinea sintaxei și corespondența numelor coloanelor cu câmpurile Entity. Room suportă interogări parametrizate prin sintaxa :paramName.

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

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertUser(user: User)

    @Query("SELECT * FROM users ORDER BY name ASC")
    fun getAllUsers(): Flow<List<User>>
}

@Insert suportă strategiile OnConflictStrategy pentru gestionarea conflictelor la inserarea înregistrărilor duplicate. Flow ca tip de returnare asigură actualizarea reactivă a UI la fiecare modificare a datelor din tabel — abonamentul se repornește automat la orice INSERT, UPDATE sau DELETE.

@Transaction pentru operații complexe

Adnotarea @Transaction garantează executarea atomică a mai multor operații într-un singur bloc tranzacțional. Room blochează baza de date pe durata execuției, prevenind condițiile de cursă la accesul concurent din mai multe fire de execuție.

Database și migrări de schemă

RoomDatabase — este o clasă abstractă care unește Entity și DAO într-un singur punct de acces la baza de date. Se creează prin Room.databaseBuilder cu specificarea versiunii schemei și a listei claselor Entity. Se recomandă crearea instanței bazei de date ca singleton prin delegat lazy pentru evitarea conexiunilor multiple.

Migrări

Migrarea în Room — este o clasă Migration care descrie scriptul SQL pentru trecerea de la versiunea veche a schemei la cea nouă. Dacă migrarea nu este furnizată la modificarea schemei, Room aruncă IllegalStateException. Acest lucru protejează împotriva pierderii accidentale a datelor utilizatorului la actualizarea aplicației.

kotlin
val migration_1_2 = object : Migration(1, 2) {
    override fun migrate(db: SupportSQLiteDatabase) {
        db.execSQL("ALTER TABLE users ADD COLUMN age INTEGER NOT NULL DEFAULT 0")
    }
}

val db = Room.databaseBuilder(
    getApplication(),
    AppDatabase::class.java,
    "app_database"
).addMigrations(migration_1_2)
 .build()

Pentru dezvoltare se poate folosi fallbackToDestructiveMigration, care șterge baza veche și creează una nouă la nepotrivirea versiunilor. Acest mod este destinat doar pentru depanare — în versiunile de producție se scriu obligatoriu migrări.

Pentru testarea bazei de date, Room oferă o clasă specială Room.inMemoryTestBuilder, care creează baza de date în memoria RAM fără salvare pe disc. După finalizarea fiecărui test, baza este distrusă automat, garantând izolarea completă a scenariilor de test. În combinație cu biblioteca android-arch-core-testing, dezvoltatorul poate gestiona ciclul de viață al bazei și poate verifica corectitudinea migrărilor fără a fi nevoie să curețe starea manual.

Performanța Room depinde direct de structura interogărilor și a indexurilor. Pentru analiza interogărilor lente, Room oferă flagul enableQueryCallback, care înregistrează toate interogările SQL cu timpul de execuție. Dezvoltatorul poate folosi acest jurnal pentru a găsi interogările care durează mai mult de 100 de milisecunde și a le optimiza prin adăugarea de indecși compuși prin adnotarea @Index în @Entity sau rescrierea subinterogărilor în JOIN-uri directe folosind @Relation.

Room suportă și criptarea bazei de date prin SQLCipher. Conectarea bibliotecii net.zetetic:android-database-sqlcipher și utilizarea SupportFactory în locul celei standard asigură criptarea transparentă a tuturor datelor pe disc fără modificarea interogărilor DAO și a structurii Entity. Acest lucru este necesar pentru aplicațiile care lucrează cu date personale ale utilizatorilor și îndeplinește cerințele GDPR și ale legii ruse 152-FZ privind protecția datelor personale. Parola de criptare poate fi stocată în Android Keystore pentru protecție împotriva extragerii prin instrumente pe dispozitive rootate.

Room cu Kotlin Coroutines și Flow

Room suportă nativ Kotlin Coroutines începând cu versiunea 2.1. Metodele DAO pot fi funcții suspend care execută interogări în fundal fără a bloca firul principal. Room gestionează automat dispatcher-ele, folosind Dispatchers.IO pentru interogările de citire și scriere.

Pentru interogări reactive, Room returnează Flow — un flux rece de date care emite o nouă valoare la fiecare modificare a tabelului afectat. ViewModel se abonează la Flow prin stateIn sau collect, asigurând actualizarea automată a UI fără notificarea manuală a adaptorului.

Room suportă și Paging 3 printr-o implementare specială PagingSource care încarcă datele paginat din SQLite. Acest lucru este eficient pentru liste mari cu mii de înregistrări: Paging 3 încarcă doar rândurile vizibile pe ecran și le actualizează automat la modificări în baza de date.

Folosiți Paging 3 cu Room la afișarea fluxului de știri, a jurnalului de operații sau a listei de produse cu posibilitatea de acces offline și derulare infinită.

Întrebări frecvente

Cu ce se deosebește Room de SQLiteOpenHelper?

Room automatizează crearea tabelelor, conversia Cursor în obiecte și verificarea SQL la compilare. SQLiteOpenHelper necesită scrierea manuală a schemei, procesarea Cursor și nu verifică interogările înainte de lansarea aplicației, ceea ce crește riscul de erori.

Este necesar să scriu migrări pentru fiecare modificare a schemei?

Da, la modificarea Entity (adăugare/ștergere câmp, schimbare tip) este necesară migrarea. Fără ea, Room aruncă IllegalStateException la pornire. Pentru dezvoltare se poate activa fallbackToDestructiveMigration, dar în versiunea de producție sunt obligatorii scripturi corecte de migrare.

Suportă Room relații între tabele?

Room suportă @ForeignKey pentru operații în cascadă și @Relation pentru obiecte imbricate. Pentru interogări JOIN complexe se folosește adnotarea @Transaction cu @Query care returnează POJO cu entități imbricate prin @Embedded și @Relation.

Pot folosi Room cu Java fără Kotlin?

Da, Room este complet compatibil cu Java. În locul funcțiilor suspend se folosesc LiveData sau RxJava Observable, în loc de Flow — LiveData. Room cu Java suportă aceleași adnotări, dar necesită mai mult cod boilerplate pentru operații asincrone.

Cum funcționează criptarea bazei de date Room?

Room suportă criptarea prin SQLCipher de la Zetetic. În loc de Room.databaseBuilder folosiți SupportFactory din biblioteca net.zetetic:android-database-sqlcipher, transmițând parola de criptare. Toate datele pe disc vor fi criptate transparent pentru interogările DAO.

Rezumat

  • Room — bibliotecă ORM Jetpack pentru SQLite cu verificare SQL la compilare.
  • @Entity descrie tabelul, @PrimaryKey — identificatorul, @ColumnInfo — numele coloanei.
  • @Dao conține metode cu @Query, @Insert, @Update și @Delete pentru acces la date.
  • RoomDatabase unește Entity și DAO, se creează prin Room.databaseBuilder.
  • Migrările (Migration) descriu scripturi SQL pentru modificarea schemei fără pierdere de date.
  • Room suportă nativ Kotlin Coroutines (suspend) și Flow pentru actualizări reactive ale UI.
  • Pentru liste mari folosiți Paging 3 cu Room prin PagingSource pentru încărcare paginată.

Vom dezvolta o aplicație mobilă la cheie

IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.

Discutați proiectul

Citiți și