Skip to content

Swift 损坏、备份、修复

sanhuazhang edited this page Dec 20, 2017 · 5 revisions

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

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

损坏检测

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

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

元数据备份

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

DispatchQueue.global(qos: .background).async {
    Timer.scheduledTimer(withTimeInterval: 5 * 60, repeats: true) {_ in
	    let backupPassword = "backupPassword".data(using: .ascii)
        try? database.backup(withKey: backupPassword)
    }
}

元数据通常只有几 kb 大小,且属于读操作,可以与其他操作并发执行。因此备份不会对性能产生大的影响。

数据修复

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

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

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

//view.startLoading()
DispatchQueue.global(qos: .background).async {
    let newDatabase = Database(withPath: "newPath")
    try? newDatabase.recover(fromPath: pathToCorruptedDatabase, 
                             withPageSize: 4096, 
                             databaseKey: corruptedDatabaseKey, 
                             backupKey: backupKey)
    //DispatchQueue.main.async {
    //    view.stopLoading()
    //}
}

对于可再生的数据,如可从服务端重新拉取的数据,直接将数据库删掉重建是更好的恢复手段。

Clone this wiki locally