Android Room数据库的基本使用

一、什么是Room

1.1 Room简介

Room是Android Jetpack组件库中的一部分,对SQLite进行了封装,简化了对SQLite数据库的操作,让开发者使用面向对象的方式(通过Java/Kotlin)来操作SQLite数据库,从而避免了编写大量繁琐的SQL代码和解析数据。

1.2 三大核心组件
  • Entity(实体类):用于表示数据库表的数据结构。
  • DAO(Data Access Object):用于定义数据库操作的方法。
  • Database(数据库类):用于创建数据库实例,并将 Entity 和 DAO 关联起来

二、集成Room

在app下的build.gradle下添加:

Kotlin 复制代码
//数据库创建成功,会有类似以下目录,以自己的为准\build\generated\source\kapt\release\com\xxx\xxx\drive\database\AppDatabase_Impl
    def room_version = "2.5.1"
    kapt "androidx.room:room-compiler:$room_version"
    implementation "androidx.room:room-runtime:$room_version"
    implementation "androidx.room:room-ktx:$room_version"

//这里注意:如果是某一个moudle中要使用room数据库,建议直接将库集成到moudle中的build.gradle中,博主这里遇到将root相关库集成到基类的build.gradle中,一直报错,提示生成数据库失败,上面的AppDatabase_Impl文件无法生成

三、使用示例

3.1 创建实体类 (Entity)
Kotlin 复制代码
/**
 * @Description : LocalUploadRecord 数据库实体类,根据项目需求,定义自己的字段即可
 */
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity(tableName = "upload_records")
data class LocalUploadRecord(
    @PrimaryKey(autoGenerate = true)
    val id: Int? = null,
    @ColumnInfo(name = "phone_id")
    val phoneId: String,//云机ID
    @ColumnInfo(name = "phone_biz_id")
    val phoneBizId: String,//云机业务ID
    @ColumnInfo(name = "user_id", index = true)
    val userId: String,//登录返回的用户id
    @ColumnInfo(name = "file_name")
    val fileName: String,//文件名(含后缀)
    @ColumnInfo(name = "file_path")
    val filePath: String,//文件路径
    @ColumnInfo(name = "phone_name")
    val phoneName: String,//云机名称
    @ColumnInfo(name = "file_status")
    var fileStatus: FileStatus,//WAITING, UPLOADING, SUCCESS, FAILED,INSTALLING,INSTALL_FAIL,INSTALL_SUCCESS
    @ColumnInfo(name = "file_time")
    val fileTime: Long,//文件操作时间-时间戳:毫秒
    @ColumnInfo(name = "file_size")
    val fileSize: Long = 0,//文件大小,字节
    @ColumnInfo(name = "err_message")
    var errMessage: String = "",
    @ColumnInfo(name = "reserved_field1")
    var reservedField1: String = "",//预留字段1
    @ColumnInfo(name = "reserved_field2")
    var reservedField2: String = "",//预留字段2
    @ColumnInfo(name = "reserved_field3")
    var reservedField3: String = "",//预留字段3
)

各注解作用:

  • @Entity(tableName = "user-room"):标记这是一个数据库表,同时指定表名
  • @PrimaryKey(autoGenerate = true):设置主键并启用自动生成
  • @ColumnInfo(name = "user_age"):设置列名
3.2 创建数据访问对象(DAO)

创建一个接口定义数据库操作: @Dao

Kotlin 复制代码
/**
 * @Description : UploadRecordDao 创建数据访问对象(DAO)
 * @Dao:标记这是一个数据访问对象接口
 * @Insert、@Update、@Delete:由Room 提供的便捷注解,可以自动生成对应 SQL
 * @Query:自定义 SQL 查询,:参数名表示方法参数
 */
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Update
import kotlinx.coroutines.flow.Flow

@Dao
interface UploadRecordDao {

    /**
     * 插入一条数据
     */
    @Insert
    fun insert(record: LocalUploadRecord): Long


    /**
     * 删除最老的数据(按时间戳升序)
     */
    @Query("DELETE FROM upload_records WHERE id IN (SELECT id FROM upload_records WHERE user_id = :userId ORDER BY file_time ASC LIMIT :count)")
    fun deleteOldest(userId: String,count:Int)

    /**
     * 删除一条记录
     */
    @Delete
     fun delete(record: LocalUploadRecord)


    /**
     * 更新一条记录
     */
    @Update
    fun update(record: LocalUploadRecord)

    /**
     * 根据userId获取所有记录
     */
    @Query("SELECT * FROM upload_records WHERE user_id = :userId ORDER BY file_time DESC")
    fun getRecordsByUser(userId: String): Flow<List<LocalUploadRecord>>


    /**
     * 根据userId和FileStatus获取记录
     */
    @Query("SELECT * FROM upload_records WHERE user_id = :userId AND file_status IN (:statusList) ORDER BY file_time DESC")
    fun getRecordsByUser(userId: String,statusList: List<FileStatus>):List<LocalUploadRecord>


    /**
     * 分页获取记录
     */
    @Query("SELECT * FROM upload_records WHERE user_id = :userId ORDER BY file_time DESC LIMIT :pageSize OFFSET :offset")
    fun getRecordsByUserPaged(userId: String, pageSize: Int, offset: Int): List<LocalUploadRecord>

    /**
     * 根据userId查询记录数
     */
    @Query("SELECT COUNT(*) FROM upload_records WHERE user_id = :userId")
    fun getRecordCountByUser(userId: String): Int

    /**
     * 根据id查询一条记录
     */
    @Query("SELECT * FROM upload_records WHERE id = :id")
//    suspend fun getRecordById(id: Long): UploadRecord 低版本在Dao中不能加suspend关键字,会报错,2.6.1中不会
    fun getRecordById(id: Long): LocalUploadRecord


    /**
     * 删除用户的所有数据
     */
    @Query("DELETE FROM upload_records WHERE user_id = :userId")
     fun deleteAllByUserId(userId: String): Int


    /**
     * 根据id 批量删除数据
     */
    @Query("DELETE FROM upload_records WHERE id IN (:ids)")
     fun deleteByIds(ids: List<Long>): Int
}

各注解作用:

  • @Dao:标记这是一个数据访问对象接口
  • @Insert、@Update、@Delete:由Room 提供的便捷注解,可以自动生成对应 SQL
  • @Query:自定义 SQL 查询,:参数名表示方法参数
3.3 创建数据库类

创建一个抽象类用于扩展 RoomDatabase:

Kotlin 复制代码
/**
 * @Description : UploadDatabase 创建数据库类
 * @Database(entities = {MyUser.class}, version = 1):标记数据库类,指定包含的表和版本号
 * Migration:定义数据库版本迁移逻辑
 * 关于数据库迁移:
 * 数据库迁移的核心作用是在修改数据库结构后(比如在实体类中添加新字段或是在库中添加新表),安全、无损地将旧版本数据库升级到新版本,同时保留用户的原有数据。
 * 版本迁移逻辑:必须增加数据库的版本号,并提供一个Migration对象来告诉Room如何从旧版本正确迁移到新版本。
 */
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase

@Database(
    entities = [LocalUploadRecord::class],
    version = 1,
    exportSchema = false
)
abstract class UploadDatabase : RoomDatabase() {
    abstract fun uploadRecordDao(): UploadRecordDao

    companion object {
        @Volatile
        private var INSTANCE: UploadDatabase? = null

        fun getInstance(context: Context): UploadDatabase {
            return INSTANCE ?: synchronized(this) {
                val instance = Room.databaseBuilder(
                    context.applicationContext,
                    UploadDatabase::class.java,
                    "upload_database"
                ).build()
                INSTANCE = instance
                instance
            }
        }
    }
}

各注解作用:

  • @Database(entities = {MyUser.class}, version = 1):标记数据库类,指定包含的表和版本号
  • Migration:定义数据库版本迁移逻辑
3.4 定义一个数据库管理类
Kotlin 复制代码
import android.content.Context
import android.util.Log
import com.android.base.kits.KLog
import com.yixin.cloudphone.drive.data.bean.PagedResult
import com.yixin.cloudphone.drive.util.Constant
import kotlinx.coroutines.flow.Flow

/**
 * @Description : UploadDatabaseManager
 */
class UploadDatabaseManager(private val context: Context) {
    //每个用户最大存储上传记录个数
    private val RECORD_LIMIT_COUNT=1000
    private val database: UploadDatabase by lazy {
        UploadDatabase.getInstance(context)
    }

    private val dao: UploadRecordDao by lazy {
        database.uploadRecordDao()
    }


    /**
     * 新增记录
     * 每个用户id最多1000条数据,超过的要删除掉
     */
     fun insertUploadRecord(record: LocalUploadRecord): Long {
            val id=dao.insert(record)
            val count=dao.getRecordCountByUser(record.userId)
            if (count>RECORD_LIMIT_COUNT){
                // 删除超过1000条的最老记录
                val deleteCount=count-RECORD_LIMIT_COUNT
                if(deleteCount>0){
                    dao.deleteOldest(record.userId,deleteCount)
                    KLog.d(Constant.TAG,"insertUploadRecord deleteOldest,sumSize:$count, deleteCount:$deleteCount")
                }
            }
            return id
    }

    //更新上传记录
     fun updateUploadRecord(record: LocalUploadRecord) {
        dao.update(record)
    }

    // 获取用户的所有上传记录(Flow版本,用于观察数据变化)
    fun getUploadRecordsByUser(userId: String): Flow<List<LocalUploadRecord>> {
        return dao.getRecordsByUser(userId)
    }

    // 根据userId和FileStatus获取记录
    fun getUploadRecordsByUser(userId: String,statusList: List<FileStatus>): List<LocalUploadRecord>{
        return dao.getRecordsByUser(userId,statusList)
    }



    // 分页获取用户的上传记录
    suspend fun getUploadRecordsPaged(
        userId: String,
        page: Int,
        pageSize: Int = 20
    ): PagedResult<LocalUploadRecord> {
        val offset = (page - 1) * pageSize
        val records = dao.getRecordsByUserPaged(userId, pageSize, offset)
        val totalCount = dao.getRecordCountByUser(userId)
        val totalPages = (totalCount + pageSize - 1) / pageSize

        return PagedResult(
            data = records,
            currentPage = page,
            pageSize = pageSize,
            totalCount = totalCount,
            totalPages = totalPages
        )
    }

    // 根据ID获取记录
     fun getRecordById(id: Long): LocalUploadRecord? {
        return dao.getRecordById(id)
    }
}
3.5 使用数据库
Kotlin 复制代码
//在Activity或viewmoudle中使用数据库
private val roomManager: UploadDatabaseManager by lazy {
        UploadDatabaseManager(VCApplication.getInstance())
    }


//查询数据库数据,使用时应该在线程中调用,数据库操作属于耗时操作

    viewModelScope.launch(Dispatchers.IO) {
    val fileList=roomManager.getUploadRecordsByUser(userId)
   }

这里重点说一下,Flow中的很好用,可以看下博主示例Dao中这里的Flow<List<LocalUploadRecord>>,这样子定义后,如果数据库有更新,会自动收到通知,不用自己主动查询。

相关推荐
倔强的石头_2 小时前
【金仓数据库】ksql 指南(五) —— 创建与管理索引和视图(KingbaseES 查询优化核心)
数据库
cypking2 小时前
三、NestJS 开发实战文档-->集成 MySQL(TypeORM)
前端·数据库·mysql·adb·node.js
码农水水2 小时前
大疆Java面试被问:Spring事务的传播行为详解
java·数据库·spring
逍遥德2 小时前
mysql-8.4.7-winx64.zip 安装/运行
数据库·mysql
lkbhua莱克瓦242 小时前
基础-约束
android·开发语言·数据库·笔记·sql·mysql·约束
falldeep2 小时前
LeetCode高频SQL50题总结
数据结构·数据库·sql·算法·leetcode·职场和发展
万邦科技Lafite2 小时前
淘宝开放API获取订单信息教程(2025年最新版)
java·开发语言·数据库·人工智能·python·开放api·电商开放平台
胡闹542 小时前
MyBatis-Plus 更新字段为 null 为何失效?
java·数据库·mybatis
戴西软件2 小时前
CAxWorks.VPG车辆工程仿真软件:打造新能源汽车安全的“数字防线“
android·大数据·运维·人工智能·安全·低代码·汽车