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
| 特性 | SQLite | Room |
|---|---|---|
| SQL 校验 | 运行时 | 编译时 |
| 对象映射 | 手动 Cursor 解析 | 自动映射 |
| 响应式查询 | 不支持 | Flow / LiveData |
| 迁移 | 手动写 SQL | Migration 框架 |
| 测试 | 困难 | 内存数据库测试 |
| 协程支持 | 无 | suspend 函数 |
常见面试问题
Q1: Room 如何实现编译时 SQL 校验?
答案:
Room 使用 注解处理器(KSP / kapt) 在编译时解析 @Query 中的 SQL:
- 检查 SQL 语法是否正确
- 检查表名、列名是否与
@Entity匹配 - 检查返回类型与列是否对应
- 生成 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 查询并发射新值。这实现了数据库变更的实时监听。