问题描述:在服务端存储APP List数据库,在客户端下载数据库db文件。而后从db文件读取的内容总是缺少两条记录;服务端数据库存储的时候写入的数据也不完整。这些问题只在Android 9.0 Pie系统上才发生。
解决:sqLiteDatabase.disableWriteAheadLogging();
WAL
原文链接:https://blog.csdn.net/qq_41566159/article/details/97532070
在默认情况下 SQLite 的事务原子提交和回滚使用的是 rollback journal 模式。但是在 3.7.0 版本(Android 9.0)中 SQLite 引入了一种新的日志模式 Write-Ahead Log (常简写为 WAL )。
sqlite是支持write ahead logging(WAL)模式的,开启WAL模式可以提高写入数据库的速度,读和写之间不会阻塞,但是写与写之间依然是阻塞的,但是如果使用默认的TRUNCATE模式,当写入数据时会阻塞android中其他线程或者进程的读操作,并发降低。 相反,使用WAL可以提高并发。 由于使用WAL比ROLLBACK JOURNAL的模式减少了写的I/O,所以写入时速度较快,但是由于在读取数据时也需要读取WAL日志验证数据的正确性,所以读取数据相对要慢。 所以大家也要根据自己应用的场景去使用这种模式。
工作原理
默认的 rollback journal 模式工作原理大致为:写操作进行前进行数据库文件拷贝,然后对数据库进行写操作。如果发生 Crash 或者 rallback 则将日志中的原始内容回滚到数据库中进行恢复操作,否则在 Commit 完成时删除日志文件。
WAL 模式则采用了相反的做法。在进行数据库写操作时,它会先复制一份原始数据到日志文件中并且将写操作也更新到日志文件中而原有数据库内容则保存不变。如果事务失败,WAL 中的记录会被忽略;如果事务成功,它将在随后的某个时间被写回到数据库文件中二该步骤被称为 Checkpoint。
在读的时候,SQLite 将在 WAL 文件中搜索,找到最后一个写入点,记住它,并忽略在此之后的写入点(这保证了读写和读读可以并行执行);随后,它确定所要读的数据所在页是否在 WAL 文件中,如果在,则读 WAL 文件中的数据,如果不在,则直接读数据库文件中的数据。
WAL性能
优点:
1.读和写可以完全地并发执行,不会互相阻塞(但是写之间仍然不能并发)。
2.WAL在大多数情况下,拥有更好的性能(因为无需每次写入时都要写两个文件)。
3.磁盘I/O行为更容易被预测。
缺点:
1.访问数据库的所有程序必须在同一主机上,且支持共享内存技术。
2.每个数据库现在对应3个文件:<yourdb>.db,<yourdb>-wal,<yourdb>-shm。
3.当写入数据达到GB级的时候,数据库性能将下降。
4.3.7.0之前的SQLite无法识别启用了WAL机制的数据库文件。
WAL引入的兼容性问题
在启用了WAL之后,数据库文件格式的版本号由1升级到了2,因此,3.7.0之前的SQLite无法识别启用了WAL机制的数据库文件。
禁用WAL会使数据库文件格式的版本号恢复到1,从而可以被SQLite 3.7.0之前的版本识别。
如果对读写并发的要求低可以每次数据库打开时禁用WAL模式,即可完成APP的版本兼容。
网友评论