Room 持久化库:Android 本地 SQLite 抽象
FreeGuideOnline
最新
2026-06-17
Room 是什么?
Room 是 Android Jetpack 组件之一,旨在 SQLite 基础上提供一个抽象层。它简化了数据库操作,帮你处理模板代码,并在编译时校验 SQL 语句的正确性。
为什么选择 Room?
- 编译期 SQL 校验,避免运行时错误。
- 与 LiveData、Flow、RxJava 等可观察类型无缝集成。
- 减少样板代码,提供注解驱动的 API。
- 支持数据库迁移与类型转换器。
Room 的核心三要素
Room 主要由三个部分组成:
- Entity – 表示数据库中的一张表。
- DAO(Data Access Object) – 提供操作数据库的方法。
- Database – 持有所有 DAO 和 Entity 的抽象类,负责数据库创建和版本管理。
三者关系如下:
Database 包含多个 Entity,并暴露对应的 DAO 用于查询。
快速上手:7 步搭建 Room 数据库
步骤 1:添加依赖
在模块级 build.gradle 中添加:
plugins {
id 'kotlin-kapt' // 如果使用 Kotlin
}
dependencies {
def room_version = "2.6.1" // 请使用最新版本
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version" // Java
kapt "androidx.room:room-compiler:$room_version" // Kotlin
// 可选 - 与 Kotlin 协程 / Flow 集成
implementation "androidx.room:room-ktx:$room_version"
}
步骤 2:创建 Entity
Entity 表示数据库中的一张表。用 @Entity 注解标注数据类,并定义主键。
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "users")
data class User(
@PrimaryKey(autoGenerate = true) val id: Int = 0,
val name: String,
val age: Int,
val isActive: Boolean = true
)
tableName自定义表名,默认为类名。@PrimaryKey声明主键,autoGenerate使其自增。- 支持使用
@ColumnInfo(name = "custom_name")自定义列名。
步骤 3:创建 DAO
DAO 负责操作数据库,通过接口或抽象类定义方法,用注解标识 SQL。
import androidx.room.*
import kotlinx.coroutines.flow.Flow
@Dao
interface UserDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertUser(user: User)
@Update
suspend fun updateUser(user: User)
@Delete
suspend fun deleteUser(user: User)
@Query("SELECT * FROM users WHERE id = :userId")
suspend fun getUserById(userId: Int): User?
@Query("SELECT * FROM users ORDER BY name ASC")
fun getAllUsers(): Flow<List<User>> // 返回 Flow 实现观察
}
@Insert、@Update、@Delete提供便捷增删改。@Query可编写原生 SQL,支持编译期校验。- 返回类型可以是
Flow、LiveData或suspend函数。
步骤 4:创建 Database 类
定义抽象类继承 RoomDatabase,列出所有 Entity 和抽象 DAO。
import androidx.room.Database
import androidx.room.RoomDatabase
@Database(entities = [User::class], version = 1, exportSchema = false)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}
步骤 5:实例化数据库
推荐在 Application 类中使用单例模式创建数据库,避免多次初始化。
import android.app.Application
import androidx.room.Room
class MyApplication : Application() {
companion object {
lateinit var database: AppDatabase
}
override fun onCreate() {
super.onCreate()
database = Room.databaseBuilder(
applicationContext,
AppDatabase::class.java,
"app_database"
).build()
}
}
步骤 6:执行数据库操作
在协程作用域中调用 DAO 方法。
class UserRepository(private val userDao: UserDao) {
val allUsers: Flow<List<User>> = userDao.getAllUsers()
suspend fun addUser(user: User) {
userDao.insertUser(user)
}
}
步骤 7:观察数据
在 Activity 或 Fragment 中使用 Flow 或 LiveData 观察数据变化。
lifecycleScope.launch {
repository.allUsers.collect { users ->
// 更新 UI
adapter.submitList(users)
}
}
进阶知识
类型转换器 (TypeConverter)
Room 默认只支持基本数据类型。存储复杂数据(如 Date、List)需要自定义类型转换器。
class Converters {
@TypeConverter
fun fromTimestamp(value: Long?): Date? {
return value?.let { Date(it) }
}
@TypeConverter
fun dateToTimestamp(date: Date?): Long? {
return date?.time
}
}
在 Database 中声明:
@Database(entities = [User::class], version = 1, exportSchema = false)
@TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() { ... }
定义表关系
Room 不支持直接存储对象引用,但你可以通过嵌套类或关联查询实现关系。
示例:一对多关系
// User 表不变
data class UserWithPets(
@Embedded val user: User,
@Relation(
parentColumn = "id",
entityColumn = "ownerId"
)
val pets: List<Pet>
)
@Query("SELECT * FROM users")
suspend fun getUsersWithPets(): List<UserWithPets>
数据库迁移
修改 Entity 结构后需提升 version 并实现 Migration。
val MIGRATION_1_2 = object : Migration(1, 2) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE users ADD COLUMN last_login INTEGER")
}
}
Room.databaseBuilder(applicationContext, AppDatabase::class.java, "app_database")
.addMigrations(MIGRATION_1_2)
.build()
若不在意数据丢失,可使用 fallbackToDestructiveMigration(),但不推荐生产环境。
测试 Room 数据库
Room 提供内存数据库快速测试。
@RunWith(AndroidJUnit4::class)
class UserDaoTest {
private lateinit var database: AppDatabase
private lateinit var userDao: UserDao
@Before
fun setUp() {
val context = ApplicationProvider.getApplicationContext<Context>()
database = Room.inMemoryDatabaseBuilder(context, AppDatabase::class.java).build()
userDao = database.userDao()
}
@After
fun tearDown() {
database.close()
}
@Test
fun insertAndGetUser() = runTest {
val user = User(name = "Test", age = 25)
userDao.insertUser(user)
val result = userDao.getUserById(1)
assertEquals("Test", result?.name)
}
}
最佳实践建议
- 为每个实体单独设计 DAO 接口,保持职责单一。
- 使用
Flow或LiveData实现响应式数据层。 - 避免在主线程执行数据库操作(除非使用
allowMainThreadQueries(),但强烈不推荐)。 - 生产环境务必规划好迁移策略。
- 善用
@Transaction确保多表操作的原子性。 - 利用
@RewriteQueriesToDropUnusedColumns等注解优化查询。 - 使用
@ForeignKey定义外键约束,保证数据完整性。
总结
Room 通过简洁的注解和编译期检查,将 Android 本地数据库开发的复杂度降到最低。掌握 Entity、DAO 和 Database 三大支柱后,你可以快速构建出可靠、可维护的持久化层。结合协程和 Flow,更能实现流畅的响应式数据流。