Jetpack Room 数据库使用完全指南
Room 是 Android Jetpack 组件中的一个 SQLite ORM 库,提供了更简单的数据库访问抽象层。以下是全面且深入的 Room 使用详解。
1、基础配置
Gradle 依赖
// 当前最新稳定版本
def room_version = "2.6.1"
dependencies {
implementation "androidx.room:room-runtime:$room_version"
// 根据项目选择以下之一:
kapt "androidx.room:room-compiler:$room_version" // Kotlin 注解处理
// annotationProcessor "androidx.room:room-compiler:$room_version" // Java 注解处理
// 可选扩展
implementation "androidx.room:room-ktx:$room_version" // Kotlin 协程支持
implementation "androidx.room:room-paging:$room_version" // Paging集成
}
2、核心组件架构
Room三大组件关系:
Entity → Database ←→ Dao ↔ Repository ↔ ViewModel ↔ UI
3、实体(Entity)定义
基本实体示例
@Entity(tableName = "users",
indices = [Index(value = ["last_name", "address"], unique = true)])
data class User(
@PrimaryKey(autoGenerate = true)
val id: Long = 0,
@ColumnInfo(name = "first_name")
val firstName: String,
@ColumnInfo(name = "last_name")
val lastName: String,
@Ignore
val tempToken: String? = null,
@Embedded
val address: Address
)
data class Address(
val street: String,
val city: String,
val postalCode: String
)
重要注解说明
注解 用途 参数选项
@Entity 标记数据表 tableName, indices等
@PrimaryKey 主键 autoGenerate
@ColumnInfo 列配置 name, defaultValue等
@Ignore 忽略字段 -
@Embedded 嵌套对象 prefix
@ForeignKey 外键约束 entity, parentColumns等
4、数据访问对象(Dao)
完整的DAO接口示例
@Dao
interface UserDao {
// CRUD基础操作
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(user: User): Long
@Update
suspend fun update(user: User): Int
@Delete
suspend fun delete(user: User): Int
// 查询方法
@Query("SELECT * FROM users ORDER BY last_name ASC")
fun getAllUsers(): Flow<List<User>>
@Query("SELECT * FROM users WHERE id = :userId")
suspend fun getUserById(userId: Long): User?
// 复杂查询
@Query("""
SELECT * FROM users
WHERE first_name LIKE :name || '%'
AND city = :city
LIMIT :limit
""")
fun searchUsers(name: String, city: String, limit: Int = 10): Flow<List<User>>
// 事务操作
@Transaction
suspend fun updateUserWithLog(oldUser: User, newUserData: User) {
delete(oldUser)
insert(newUserData.copy(id = oldUser.id))
// 可以在此记录变更日志等其他操作
}
}
5、数据库实例管理
数据库类定义
@Database(
entities = [User::class, Product::class, Order::class],
version = 1,
exportSchema = true,
autoMigrations = [
AutoMigration(from = 1, to = 2),
AutoMigration(from = 2, to = 3, spec = AppDatabase.Migration2To3::class)
]
)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
abstract fun productDao(): ProductDao
companion object {
@Volatile
private var INSTANCE: AppDatabase? = null
fun getInstance(context: Context): AppDatabase {
return INSTANCE ?: synchronized(this) {
INSTANCE ?: buildDatabase(context).also { INSTANCE = it }
}
}
private fun buildDatabase(context: Context): AppDatabase {
return Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
"app_database.db"
)
.addCallback(object : Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
// 初始化数据
}
})
.addMigrations(MIGRATION_1_2, MIGRATION_3_4)
.setQueryExecutor(Executors.newFixedThreadPool(4)) // 自定义线程池
.enableMultiInstanceInvalidation() // 多进程支持
.fallbackToDestructiveMigrationOnDowngrade() // 降级保护
.build()
}
// 手动迁移示例
private val MIGRATION_1_2 = object : Migration(1, 2) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE users ADD COLUMN middle_name TEXT DEFAULT NULL")
}
}
}
}
6、进阶主题
6.1、数据库迁移策略
自动迁移(AutoMigration):适用于简单结构变化
手动迁移:复杂结构调整时需要
测试迁移:使用MigrationTestHelper
6.2、关联查询处理
一对多关系
data class UserWithOrders(
@Embedded val user: User,
@Relation(
parentColumn = "id",
entityColumn = "user_id"
)
val orders: List<Order>
)
@Transaction
@Query("SELECT * FROM Users")
fun getUsersWithOrders(): List<UserWithOrders> 多对多关系
@Entity(primaryKeys = ["playlistId", "songId"])
data class PlaylistSongCrossRef(
val playlistId: Long,
val songId: Long
)
data class PlaylistWithSongs(
@Embedded val playlist: Playlist,
@Relation(
parentColumn = "playlistId",
entityColumn = "songId",
associateBy = Junction(PlaylistSongCrossref::class)
)
val songs: List<Song>
)
6.3、TypeConverter 使用
class Converters {
@TypeConverter
fun fromTimestamp(value: Long?) = value?.let { Date(it) }
@TypeConverter
fun dateToTimestamp(date: Date?) = date?.time
}
@Database(..., converters = [Converters::class])
abstract class AppDatabase : RoomDatabase()
7、最佳实践
生命周期管理:
在Application中初始化数据库
ViewModel中持有DAO引用
线程策略:
主线程禁止直接访问
使用协程或RxJava进行异步操作
性能优化:
使用IN语句代替多个OR条件
合理创建索引
@Query("SELECT * FROM users WHERE region IN (:regions)")
suspend fun loadUsersByRegions(regions: List<String>): List<User> 测试建议:使用AndroidJUnit4运行Instrumentation测试,内存数据库用于单元测试
Room.inMemoryDatabaseBuilder(context, TestDatabase::class.java).build()
8、常见问题解决
Schema导出失败,在defaultConfig中添加:
javaCompileOptions {
annotationProcessorOptions {
arguments += ["room.schemaLocation": "$projectDir/schemas".toString()]
}
} Pre-packaged数据库:
.createFromAsset("database/prepopulated.db") 调试技巧,开启SQL日志:
.setJournalMode(RoomDatabase.JournalMode.TRUNCATE)
这个指南涵盖了Room的主要功能和最佳实践,可根据具体需求进行调整和完善。