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

SQLite磁盘I/O错误排查及手动SQL与GRDB查询结果不一致问题

排查SQLite Disk I/O Error及GRDB查询结果不一致问题

一、手动SQL查询与GRDB fetchAll结果不一致的原因

你直接打印db.execute(sql: ...)的结果是错误的——execute方法返回的是Statement对象(SQL语句的执行句柄),而非实际查询结果集。打印这个对象只会输出它的内存地址或类描述,自然和User.all().fetchAll(db)返回的User对象数组呈现不同内容。

要正确获取手动SQL的查询结果,需要调用fetchAll方法:

try await db.writer.write { db in
    // 获取原始行数据
    let rawRows = try db.fetchAll(sql: "SELECT * from \"user\"")
    print("Pre save raw rows: \(rawRows)")
    
    // 映射为User对象,与GRDB的all()结果一致
    let users = try User.fetchAll(db, sql: "SELECT * from \"user\"")
    print("Pre save users: \(users)")
    
    try model.save(db)
}

另外需要确认:GRDB默认会将结构体名(User)转为小写表名(user),你的手动SQL里用\"user\"是正确的;但若通过TableRecord协议自定义过表名,需确保手动SQL的表名与GRDB使用的一致。

二、SQLite Error 10 (Disk I/O Error) 排查方向

结合你的登录/登出流程,从以下几点排查:

  1. 错误被隐藏:你的save和delete方法的catch块是空的,导致操作失败的错误无法被捕获和查看。先补上错误打印,确认具体触发时机:
func save(_ model: Model) {
   Task {
      do {
         try await db.writer.write { db in
             try model.save(db)
         }
      } catch {
          print("Save failed: \(error)") // 新增错误打印
      }
    }
}

func delete() {
    Task {
        do {
            _ = try await db.writer.write { db in
                try Model.deleteAll(db)
            }
        } catch {
            print("Delete failed: \(error)") // 新增错误打印
        }
    }
}
  1. 并发操作冲突:登出的delete和登录的save都是异步执行,可能出现delete未完成、save就启动的情况,导致数据库文件锁定或操作冲突。可通过串行化操作解决:

    • 用串行Actor包裹数据库操作,或确保GRDB的writer实例正确管理(GRDB的writer本身是串行的,但若db实例管理不当会失效)。
  2. 数据库文件权限/路径问题:检查数据库所在目录的读写权限(比如iOS的Documents目录是否正确访问、macOS沙箱权限是否配置);磁盘空间不足也会触发disk I/O error,需确认设备剩余空间。

  3. GRDB连接生命周期问题:确保db实例(包括db.writer)是全局单例或正确管理的,避免重复初始化或提前释放导致的连接异常。

  4. save操作的行为差异:GRDB的save方法会根据记录是否存在自动选择INSERT或UPDATE。第二次登录时,若delete未执行完成,User记录仍存在,save会执行UPDATE操作,此时若数据库文件存在I/O问题,就会触发错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 17:52:21