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

iOS执行SQLite查询报database is locked且后续写操作失效如何解决

问题根因
  • 核心逻辑缺陷:当查询命中结果时,代码直接在while循环内提前返回,未执行sqlite3_finalize(queryStatement)释放预编译语句资源。未被销毁的预编译语句会持续持有SQLite的读锁,SQLite的读写锁机制下,残留的读锁会阻塞所有写操作(insert/delete/update),但不会影响其他读操作,完全匹配你遇到的故障表现。
  • 潜在风险点:使用字符串拼接构造SQL语句存在SQL注入风险,也不利于预编译语句复用。
修复方案

使用Swift的defer语法保证无论函数以任何路径退出,都会自动执行预编译语句的释放逻辑,同时建议替换为参数化查询规避注入风险。修复后的代码如下:

func readIdComposicagoPelagem(_ idEspecie:Int, _ idPelagem:Int, _ idStPelagem:Int) -> Int {
    let idComp = 0
    // 使用占位符构造参数化查询SQL
    let queryStatementString = "SELECT idComp FROM RES_COMP_PELAGEM where idEspecie = ? and idPelagem = ? and idStPelagem = ?;"
    var queryStatement: OpaquePointer? = nil
    
    if sqlite3_prepare_v2(db, queryStatementString, -1, &queryStatement, nil) == SQLITE_OK {
        // 绑定查询参数,占位符索引从1开始
        sqlite3_bind_int(queryStatement, 1, Int32(idEspecie))
        sqlite3_bind_int(queryStatement, 2, Int32(idPelagem))
        sqlite3_bind_int(queryStatement, 3, Int32(idStPelagem))
        
        // 退出当前作用域时自动执行,无论是否提前return都会释放资源
        defer {
            sqlite3_finalize(queryStatement)
        }
        
        while sqlite3_step(queryStatement) == SQLITE_ROW {
            let ident = sqlite3_column_int(queryStatement, 0)
            debugPrint("Query Result RES_COMP_PELAGEM:")
            debugPrint("ident: \(ident) ")
            return Int(ident)
        }
    } else {
        debugPrint("SELECT statement could not be prepared - RES_COMP_PELAGEM")
        // 预编译失败时也需要释放已分配的statement资源
        sqlite3_finalize(queryStatement)
    }
    
    return idComp
}
额外优化建议

如果存在多线程操作数据库的场景,建议将所有数据库操作都放到同一个串行队列中执行,避免并发操作触发不必要的锁冲突。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 11:15:05