You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

统计Room数据库待插入记录时pendingRecords最终不为零如何解决

问题原因

你遇到的pendingRecords最终不为0的问题,核心是以下几个错误:

  • DAO的insert方法没有声明为suspend,属于阻塞式调用,虽然你主动切了IO调度器,但Room原生支持协程的挂起操作,阻塞调用在高并发批量插入场景下更容易出现调度时序问题
  • pendingRecords的加减操作不是线程安全的:你在IO调度器的多线程并发环境下直接对普通变量执行++/--操作,该操作本身不是原子指令,多个协程同时操作时会出现写覆盖,导致计数丢失
  • 嵌套启动协程的逻辑冗余且容易出错:你在父协程内部又额外启动子协程执行插入,批量场景下会产生大量不必要的协程开销,同时如果父协程提前取消,部分子协程的invokeOnCompletion可能没有被正确触发
最优解决方案

1. 优先使用批量插入(性能最高)

如果是批量插入场景,不要逐条启动协程插入,直接用Room的批量插入方法,单次数据库交互即可完成,计数逻辑完全可控:
首先修改DAO:

@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertBatch(sensors: List<Pressure>)

然后修改插入逻辑:

viewModelScope.launch {
    // 批量插入前直接设置待处理总数
    pendingRecords.set(sensorDataList.size)
    // Room的suspend方法自动切IO线程,不需要手动指定调度器
    database?.pressureDao()?.insertBatch(sensorDataList)
    // 插入完成直接置0,不会有计数误差
    pendingRecords.set(0)
}

2. 如需逐条插入统计进度

如果确实需要逐条插入做进度统计,首先将pendingRecords替换为线程安全的原子类,避免并发计数错误:

// 声明原子计数类,替代原有的Int类型pendingRecords
private val pendingRecords = AtomicInteger(0)

同时修改DAO的插入方法为suspend类型:

@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(sensor: Pressure)

插入逻辑调整如下,不需要嵌套切线程,也不需要用invokeOnCompletion,直接用finally保证计数必减:

viewModelScope.launch {
    sensorDataList.forEach { sensorData ->
        pendingRecords.incrementAndGet()
        // 启动子协程执行单条插入
        launch {
            try {
                database?.pressureDao()?.insert(sensorData)
            } finally {
                pendingRecords.decrementAndGet()
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者Oliver

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 13:45:00