跳到主要内容

Room 数据库

问题

Room 是什么?它相比直接使用 SQLite 有什么优势?

答案

核心概念

Room 是 SQLite 的抽象层,提供编译时 SQL 校验流式查询对象关系映射

三大核心组件

// 1. Entity —— 定义数据表
@Entity(tableName = "users")
data class User(
@PrimaryKey(autoGenerate = true) val id: Long = 0,
@ColumnInfo(name = "user_name") val name: String,
val email: String,
val createdAt: Long = System.currentTimeMillis()
)

// 2. DAO —— 数据访问接口
@Dao
interface UserDao {
@Query("SELECT * FROM users WHERE id = :userId")
suspend fun getById(userId: Long): User?

@Query("SELECT * FROM users ORDER BY user_name")
fun getAllFlow(): Flow<List<User>> // 数据变化自动通知

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

@Update
suspend fun update(user: User)

@Delete
suspend fun delete(user: User)

@Query("DELETE FROM users")
suspend fun deleteAll()
}

// 3. Database —— 数据库定义
@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}

// 构建数据库实例
val db = Room.databaseBuilder(context, AppDatabase::class.java, "app.db")
.fallbackToDestructiveMigration() // 版本不兼容时删库重建(开发期)
.build()

数据库迁移

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

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

Room vs 直接使用 SQLite

特性SQLiteRoom
SQL 校验运行时编译时
对象映射手动 Cursor 解析自动映射
响应式查询不支持Flow / LiveData
迁移手动写 SQLMigration 框架
测试困难内存数据库测试
协程支持suspend 函数

常见面试问题

Q1: Room 如何实现编译时 SQL 校验?

答案

Room 使用 注解处理器(KSP / kapt) 在编译时解析 @Query 中的 SQL:

  1. 检查 SQL 语法是否正确
  2. 检查表名、列名是否与 @Entity 匹配
  3. 检查返回类型与列是否对应
  4. 生成 DAO 实现类(UserDao_Impl

Q2: Room 支持哪些关系查询?

答案

// 一对多 —— 用户和文章
data class UserWithPosts(
@Embedded val user: User,
@Relation(
parentColumn = "id",
entityColumn = "userId"
)
val posts: List<Post>
)

@Dao
interface UserDao {
@Transaction
@Query("SELECT * FROM users WHERE id = :userId")
suspend fun getUserWithPosts(userId: Long): UserWithPosts
}

@Relation 支持 @Embedded + @Relation 组合,Room 会自动执行两条查询。

Q3: Room 的 Flow 查询是如何工作的?

答案

当 DAO 返回 Flow<List<User>> 时,Room 会注册一个 InvalidationTracker。当该表发生任何写操作(insert/update/delete)时,InvalidationTracker 通知 Flow,Flow 重新执行 SQL 查询并发射新值。这实现了数据库变更的实时监听。

相关链接