使用WCDB中踩过的坑

使用WCDB中踩过的坑

一.遇到的问题

  • 在版本覆盖安装时,发现有些数据丢失;后通过抓包查看沙盒数据库文件时,发现WCDB数据库某张表损坏,造成数据丢失。使用WCDB中踩过的坑_第1张图片

二.调查问题过程

  1. 查看问题出现的版本4.7.6,首次安装此版本,安装时会先执行,内置数据库会被拷贝到沙盒中,由于此时有数据更新,会拉取接口,更新数据库文件,发现所有缓存数据没有问题;
  2. 首次安装上一个版本4.7.0,此时一样会先执行,内置数据库会被拷贝到沙盒中,由于此时有数据更新,会拉取接口,更新数据库文件,发现4.7.0版本,所有缓存数据也没有问题;
  3. 在第二步基础上,用4.7.6版本,覆盖安装4.7.0版本,此时,app内的执行顺序是:删除本地原有的数据库,把内置数据库会被拷贝到沙盒中,替换4.7.0版本的数据库文件,此时发现有数据更新,会拉取接口,更新数据库文件,问题出现了,WCDB中某张表损坏了,数据丢失。此时打印的日志如下:和查询表时提示一致;image
  4. 对比4.7.0版本和4.7.6版本代码,发现4.7.6版本的某张表里数据的存储格式和4.7.0有区别;在执行内置数据库会被拷贝到沙盒中前,只删除了Cache.db文件,而Cache.db-wal和Cache.db-shm文件没有被删除,此时拉取接口更新数据库时,更新到Cache.db-wal,再缓存到Cache.db时,由于格式不一致,造成表损坏。

三.SQLite中的wal和shm

  • wal全称Write Ahead Log 即预写日志,shm是日志索引文件;当每个事务对数据库执行修改时,会将修改后的日志存入到wal文件中,当事务读取数据库数据时,优先读取wal文件中读取,读不到再从数据库中读取。
  • 如何做到读写并发操作???首先事务在写入时,是将新数据写入到日志文件中,不更新db,当事务提交时,也不影响db,只是将日志持久化了。这样看,最新的数据是在日志中的,在事务读取时,首先在日志文件中,找到最近的一个end-mark(事务提交节点),在这个节点之前查找对应的数据。如果找不到,再去db中查找,这样看在极端的情况下,每次查询都要在wal文件和db中各查找一次,影响性能。为了提高性能,wal-index文件(也就是.shm文件)用来记录page号和该page在wal文件中的偏移,并且wal-index文件采用共享内存,避免了对整个wal文件的查找(共享内存也有一个弊端就是SQlite的进程不能跨机器)。
  • wal文件由32字节的首部和若干个帧组成,每个帧由24字节帧首部和一页数据组成。

四.总结

  1. 删除本地Cache.db文件时,要同时删除Cache.db-wal和Cache.db-shm文件;否则会出现,由于前后数据格式不一致时,造成数据库表损坏情况;
  2. 检测数据库损坏,做数据库修复或者删除重建库处理。

你可能感兴趣的:(IOS技术)