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
相关产品推荐
相关产品推荐

