• 损坏检测
  • 元数据备份
  • 数据修复

    数据库作为二进制文件,当内部有部分数据不一致或丢失时,可能会发生数据库损坏。数据不一致或丢失的原因较多,可能是代码问题、操作系统或文件系统故障、磁盘损坏等等。从根源上,数据库损坏是不可能完全避免的。

    因此,WCDB Swift 内建了修复工具,可以尽最大限度地将数据找回,减少数据丢失。

    损坏检测

    在监控与错误处理一章,已经提到了监控和处理错误信息了。损坏也可以用同样地方式监控,当错误类型为 SQLite 且错误码为 11 或 26 时,代表发生了数据库损坏,然后可以根据 tag 确认损坏的数据库,而后进行处理。

    1. Database.globalTrace(ofError: { (error: WCDBSwift.Error) in
    2. if error.type == .sqlite && (error.code.value == 11 || error.code.value == 26) {
    3. print("Tag: \(error.tag) is corrupted")
    4. }
    5. })

    元数据备份

    在有备份的情况,修复工具的能力将大大提升。在数据库内的数据发生变化时,元数据备份有可能会过期。因此建议在子线程定期对其备份。

    1. DispatchQueue.global(qos: .background).async {
    2. Timer.scheduledTimer(withTimeInterval: 5 * 60, repeats: true) {_ in
    3. let backupPassword = "backupPassword".data(using: .ascii)
    4. try? database.backup(withKey: backupPassword)
    5. }
    6. }
    元数据通常只有几 kb 大小,且属于读操作,可以与其他操作并发执行。因此备份不会对性能产生大的影响。

    数据修复

    数据库修复通过 recover(fromPath:withPageSize:databaseKey:backupKey:) 接口完成。它将尝试从已损坏的数据库中读出数据,并插入到新数据库中。其函数原型为:

    1. func recover(fromPath source: String, // 已损坏的数据库路径
    2. withPageSize pageSize: Int32 = 4096, // 已损坏的数据库的page size
    3. databaseKey: Data? = nil, // 已损坏的数据库的密码,若未加密,则为 nil
    4. backupKey: Data? = nil) throws // 元数据备份的密码,若备份未加密,则为 nil

    修复过程根据数据库的大小不同,需要一定的时间。建议在界面上提示等待,并在子线程进行修复。

    1. //view.startLoading()
    2. DispatchQueue.global(qos: .background).async {
    3. let newDatabase = Database(withPath: "newPath")
    4. try? newDatabase.recover(fromPath: pathToCorruptedDatabase,
    5. withPageSize: 4096,
    6. databaseKey: corruptedDatabaseKey,
    7. backupKey: backupKey)
    8. //DispatchQueue.main.async {
    9. // view.stopLoading()
    10. //}
    11. }
    对于可再生的数据,如可从服务端重新拉取的数据,直接将数据库删掉重建是更好的恢复手段。