Room : qu'est-ce que c'est, bibliothèque ORM et travail avec SQLite

Auteur : IT Sectr Publié le : 2026-03-12 Temps de lecture : 10 min

Room est une bibliothèque ORM d'Android Jetpack qui fournit une couche d'abstraction au-dessus de SQLite pour travailler avec des bases de données locales sur Android. Selon la documentation officielle sur Android Developers, 2025, Room génère automatiquement des implémentations DAO basées sur des annotations au moment de la compilation, éliminant environ 70 % du code passe-partout par rapport à l'utilisation directe de SQLiteOpenHelper. La bibliothèque effectue une validation des requêtes SQL au moment de la compilation, ce qui permet de détecter les erreurs de syntaxe avant d'exécuter l'application sur un appareil.

Points Clés

  • Room est une bibliothèque ORM d'Android Jetpack fournissant une couche d'abstraction au-dessus de SQLite pour le stockage local de données dans les applications Android.
  • Trois composants principaux : Entity (définition de table), DAO (opérations sur les données) et Database (point d'entrée de la base de données).
  • La validation des requêtes SQL au moment de la compilation est un avantage clé, permettant de trouver les erreurs avant l'installation de l'application.
  • Prise en charge intégrée de Flow, LiveData et RxJava pour l'observation réactive des changements dans la base de données.
  • Le mécanisme de migrations permet de mettre à jour le schéma de la base de données sans perdre les données utilisateur déjà sauvegardées.

Qu'est-ce que la bibliothèque Room ORM ?

Room est une bibliothèque ORM d'Android Jetpack créée par Google pour simplifier le travail avec les bases de données SQLite locales sur la plateforme Android. Elle fournit des annotations pour décrire le schéma de données et génère automatiquement des implémentations d'interfaces DAO au moment de la compilation. Contrairement à l'utilisation directe de SQLiteOpenHelper, Room libère le développeur de l'écriture d'une quantité importante de code passe-partout pour créer, ouvrir et gérer les connexions à la base de données.

La bibliothèque a été présentée lors du Google I/O 2017 dans le cadre des composants d'architecture Android. Depuis lors, Room est devenu le standard de facto pour le stockage local de données, dépassant en popularité des solutions comme GreenDAO et Realm pour Android. Selon Google, la bibliothèque est utilisée dans plus de 60 % des applications publiées sur Google Play qui travaillent avec des données locales sur l'appareil.

La caractéristique clé est la validation des requêtes SQL au moment de la compilation à l'aide d'un processeur d'annotations. Si un développeur commet une erreur dans une commande SQL, par exemple en spécifiant un nom de colonne inexistant, la compilation échouera avec une erreur avant l'installation de l'application. Cela diffère fondamentalement de l'approche SQLiteOpenHelper, où de telles erreurs ne sont détectées qu'au moment de l'exécution, souvent en production.

TypeConverters pour les types non standard

SQLite ne prend en charge que cinq types de données : TEXT, INTEGER, REAL, BLOB et NULL. Cependant, Java et Kotlin utilisent des types complexes : Date, List, Enum et des objets personnalisés. Pour les stocker, Room fournit le mécanisme TypeConverters — des méthodes statiques qui convertissent un type complexe en un type primitif compréhensible par SQLite. Par exemple, un objet Date est converti en Long (timestamp), et List<String> en une chaîne JSON via Gson ou 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()

Pour déclarer un convertisseur, il suffit d'ajouter l'annotation @TypeConverter à une méthode statique et de spécifier la classe du convertisseur dans l'annotation @TypeConverters au niveau de la base de données. Room applique automatiquement le convertisseur lors de la lecture et de l'écriture du type correspondant dans chaque requête SQL sans avoir à appeler manuellement les méthodes de conversion.

Architecture de Room : trois composants clés

Room se compose de trois composants principaux : Entity, DAO et Database. Chacun joue un rôle strictement défini et est annoté avec l'annotation correspondante. Ensemble, ils forment une couche d'accès aux données complète qui isole la logique métier de l'application des détails d'implémentation de SQLite.

Entity — Table de base de données

Entity est une classe de données qui décrit la structure d'une table dans la base de données. Chaque champ de la classe correspond à une colonne de la table, et chaque ligne dans la base de données correspond à une instance de la classe. L'annotation @Entity indique à Room que la classe est une table. Le champ avec l'annotation @PrimaryKey définit la clé primaire, qui peut être auto-incrémentée ou composite. @ForeignKey est utilisé pour les relations entre les tables, garantissant l'intégrité des données au niveau de la base de données.

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 — Opérations sur les données

DAO (Data Access Object) est une interface ou classe abstraite qui déclare des opérations pour travailler avec les données : insertion, lecture, mise à jour et suppression. Chaque opération est annotée avec @Insert, @Query, @Update ou @Delete. Room génère automatiquement l'implémentation de cette interface au moment de la compilation. L'annotation @Query est particulièrement précieuse — elle accepte une requête SQL sous forme de chaîne et valide sa correction au moment de la construction.

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 — Point d'entrée

Database est une classe abstraite étendant RoomDatabase qui sert de point d'entrée à la base de données. Elle contient une liste de toutes les Entities et fournit des méthodes abstraites pour obtenir les DAOs. La classe est annotée avec @Database, qui spécifie la version du schéma et la liste des entités. L'instance de la base de données est créée via Room.databaseBuilder avec le contexte de l'application, le nom du fichier et la classe Database.

Comment Room fonctionne avec SQLite sous le capot

Room ne remplace pas SQLite, mais fonctionne au-dessus de lui comme une couche d'abstraction. L'architecture interne comprend un processeur d'annotations, un générateur de code et un pool de connexions. Au moment de la compilation, le processeur d'annotations analyse les classes Entity, DAO et Database, puis génère des classes d'implémentation avec le suffixe _Impl. Toutes les classes générées sont placées dans le package de construction et ne sont pas visibles directement pour le développeur.

La génération de code au moment de la compilation est le mécanisme central de Room. Pour chaque interface DAO, une classe avec l'implémentation complète de toutes les méthodes annotées est générée. Les requêtes SQL de l'annotation @Query sont validées pour leur exactitude : le processeur fait correspondre les noms de colonnes avec les champs Entity et vérifie la syntaxe SQL. Si une erreur est trouvée, la construction est interrompue avec un message clair. Cela est impossible lors de l'utilisation de SQLiteOpenHelper brut, où les erreurs n'apparaissent qu'au moment de l'exécution.

Génération de code au moment de la compilation

Le processus de génération comprend trois étapes. Première — validation du schéma : le processeur vérifie que toutes les classes listées dans @Database sont des Entities valides. Deuxième — génération du corps du DAO : pour chaque méthode, une implémentation est créée en utilisant l'objet interne RoomSQLiteQuery qui exécute des requêtes préparées. Troisième — génération de la classe Database_Impl, qui gère la création et l'ouverture de la base de données, ainsi que l'initialisation de tous les objets 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 ne crée pas de pool de threads séparé pour les opérations de base de données. Par défaut, les requêtes sont exécutées dans le thread appelant avec une limitation : la lecture et l'écriture bloquent le thread. Pour le travail asynchrone, Room s'intègre avec les coroutines Kotlin via les fonctions suspend, avec LiveData via les valeurs de retour, et avec Flow via des wrappers réactifs. Cela donne au développeur la flexibilité de choisir la solution architecturale pour une tâche spécifique.

Exemple d'utilisation de Room dans une application Android

Regardons un exemple pratique de création d'une application de prise de notes utilisant Room. L'application contient une table Note avec les champs id, title, content et timestamp. Les utilisateurs peuvent ajouter, visualiser et supprimer des notes. Des coroutines sont utilisées pour les opérations asynchrones.

Configuration des dépendances Gradle

Pour intégrer Room dans un projet Android, ajoutez des dépendances au fichier build.gradle du module de l'application. Room nécessite trois composants : la bibliothèque d'exécution, le processeur d'annotations kapt et la prise en charge optionnelle des coroutines. La version de la bibliothèque est spécifiée dans une variable room_version pour faciliter la mise à jour. À partir de Room 2.4.0, KSP est pris en charge comme alternative à kapt avec des vitesses de construction plus rapides.

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"
    // Facultatif : tests
    testImplementation "androidx.room:room-testing:$room_version"
}

Après avoir configuré les dépendances, créez trois fichiers : l'Entity Note, l'interface NoteDao et la classe AppDatabase. L'Entity Note contient des champs avec les annotations @PrimaryKey et @ColumnInfo. Le DAO fournit des méthodes pour insérer, obtenir la liste et supprimer. La Database relie l'Entity et le DAO via l'annotation @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)
}

Le fichier AppDatabase est déclaré comme une classe abstraite étendant RoomDatabase. L'annotation @Database spécifie toutes les Entities pour la version actuelle et le numéro de version du schéma. Pour obtenir une instance, le modèle singleton est utilisé via la méthode build de Room.databaseBuilder avec le contexte de l'application. La mise en cache de l'instance de la base de données empêche les créations multiples qui pourraient entraîner des fuites de mémoire.

Migrations de base de données dans Room

Les Migrations dans Room sont un mécanisme pour modifier le schéma de la base de données lors de la mise à jour d'une application sans perdre les données existantes. Lorsqu'un utilisateur installe une nouvelle version avec des Entities modifiées, Room détecte l'incompatibilité de version et exécute les étapes de migration spécifiées. Sans migration, la base de données sera supprimée et recréée, entraînant la perte de toutes les données sauvegardées par l'utilisateur.

Une migration est décrite par la classe Migration, qui prend les versions de début et de fin de la base de données. À l'intérieur de la méthode migrate, une requête SQL ALTER TABLE ou CREATE TABLE est exécutée pour modifier le schéma. Room ne peut pas détecter automatiquement les changements de schéma — le développeur doit écrire une migration manuellement pour chaque modification d'Entity. À partir de Room 2.4.0, la fonctionnalité expérimentale autoMigrations est disponible pour la génération automatique de migrations.

Migrations automatiques avec autoMigrations

La fonctionnalité autoMigrations permet à Room de générer automatiquement des migrations basées sur les différences entre les versions d'Entity. Pour l'utiliser, il suffit d'ajouter l'annotation @AutoMigration à @Database et d'activer l'exportation du schéma en JSON. Room compare les schémas des versions adjacentes et génère les requêtes ALTER nécessaires. Cependant, autoMigrations ne prend en charge que les modifications rétrocompatibles : ajout de colonnes, création d'index et changement de types avec des transformations compatibles.

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()

Pour les modifications complexes, telles que le renommage de colonnes ou la fusion de tables, une migration manuelle utilisant des tables intermédiaires est nécessaire. Un scénario typique : créer une table temporaire avec l'ancien schéma, copier les données de l'ancienne table vers la nouvelle avec des transformations, supprimer l'ancienne table et renommer la temporaire. Room garantit que toutes les migrations sont exécutées dans une seule transaction, et en cas d'erreur, les modifications sont entièrement annulées.

Questions Fréquentes

En quoi Room diffère-t-il de SQLiteOpenHelper ?

Room fournit une abstraction ORM avec des annotations et une validation SQL au moment de la compilation, tandis que SQLiteOpenHelper nécessite d'écrire manuellement toutes les requêtes et de gérer les connexions. Room génère automatiquement le code pour les opérations CRUD et s'intègre avec les composants d'architecture Android, y compris LiveData et Flow.

Quels types de données Room prend-il en charge ?

Room prend en charge tous les types primitifs Java : Int, Long, Boolean, Float, Double, ainsi que String, ByteArray et Date. Pour les types complexes tels que List ou Enum, des TypeConverters sont utilisés — des méthodes de conversion statiques qui convertissent les types non standard en formats compatibles SQLite.

Peut-on utiliser Room sans coroutines ?

Oui, Room prend en charge les appels synchrones sans coroutines, mais ils bloquent le thread dans lequel ils sont exécutés. Pour un travail asynchrone, vous pouvez utiliser LiveData ou RxJava à la place des coroutines. Google recommande d'utiliser les coroutines comme méthode principale d'accès asynchrone aux données dans les nouveaux projets.

Que se passe-t-il en l'absence de migration ?

Si Room détecte une incompatibilité de version de la base de données et ne trouve pas de migration appropriée, par défaut il lance une IllegalStateException avec une description de l'erreur. Le développeur peut remplacer ce comportement par la méthode fallbackToDestructiveMigration, qui supprimera la base de données existante et en créera une nouvelle, entraînant la perte de toutes les données.

Comment Room gère-t-il les relations entre les tables ?

Room prend en charge les relations via des objets imbriqués avec l'annotation @Embedded et via des classes de relation avec l'annotation @Relation. Pour les requêtes complexes impliquant des jointures de tables, des classes POJO personnalisées sont utilisées, dont les champs sont remplis à partir des résultats de @Query avec des instructions SQL JOIN.

Résumé

  • Room est une bibliothèque ORM d'Android Jetpack qui crée une couche d'abstraction au-dessus de SQLite pour le stockage pratique des données sur l'appareil.
  • L'architecture est basée sur trois composants : Entity (schéma de table), DAO (opérations) et Database (point d'entrée).
  • La validation des requêtes SQL au moment de la compilation est le principal avantage, éliminant les erreurs d'exécution dans les requêtes.
  • La prise en charge intégrée de Flow, LiveData et RxJava permet de construire des architectures réactives avec des mises à jour automatiques de l'interface utilisateur lors des modifications de données.
  • Les migrations dans Room garantissent des mises à jour transparentes du schéma de la base de données sans perte des informations utilisateur sauvegardées.
  • La bibliothèque s'intègre avec les coroutines Kotlin via les fonctions suspend, simplifiant le travail asynchrone avec les données.
  • Pour les nouveaux projets, Room est la solution officiellement recommandée par Google pour le stockage local de données sur Android.

Nous développerons une application mobile clé en main

IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.

Discuter du projet

Lisez aussi