面试题答案
一键面试1. SQLite检测并恢复异常事务的方式
- 回滚日志(Rollback Journal)
- SQLite在执行事务时,会将对数据库文件的修改先记录到回滚日志中。回滚日志包含了将数据库还原到事务开始前状态所需的所有操作记录。
- 当系统崩溃或出现异常,事务未完成时,SQLite在重启时会检查回滚日志。如果发现有未完成事务对应的回滚日志文件,SQLite会根据回滚日志中的记录撤销未完成事务对数据库所做的修改,从而将数据库恢复到事务开始前的状态。
- 预写式日志(WAL - Write - Ahead Logging,可选模式)
- 在WAL模式下,SQLite不会直接修改数据库文件,而是将修改写入到WAL文件中。每个事务在WAL文件中追加一条记录。
- 系统崩溃后,SQLite在重启时会扫描WAL文件,确认哪些事务已经完成(通过事务记录中的元数据等信息判断),哪些事务未完成。对于未完成的事务,SQLite会忽略其在WAL文件中的记录,因为这些修改还未真正应用到数据库文件,对于已完成的事务,SQLite会将其从WAL文件中重新应用到数据库文件,以确保数据的一致性。
2. 锁状态在异常事务恢复过程中的处理
- 共享锁(Shared Locks)
- 在事务执行过程中,读取操作通常会获取共享锁。当出现异常事务时,共享锁的状态取决于事务的恢复机制。如果使用回滚日志,回滚日志中的记录会被用于撤销未完成事务,共享锁在事务撤销过程中会被释放,因为事务对数据的读取操作被撤销,不再需要持有共享锁。
- 在WAL模式下,未完成事务的共享锁会随着事务的“回滚”(即忽略未完成事务在WAL中的记录)而自动解除,因为这些事务对数据的影响未真正应用到数据库文件。
- 排它锁(Exclusive Locks)
- 写入操作会获取排它锁。在异常事务恢复过程中,如果使用回滚日志,排它锁会随着未完成事务的回滚而释放,以确保其他事务可以重新获取锁来访问相关数据。
- 在WAL模式下,未完成事务的排它锁同样会随着事务的“回滚”(忽略未完成事务记录)而解除,使得其他事务能够获取排它锁进行写入操作。
3. SQLite检测和解决死锁的机制
- 死锁检测
- SQLite使用一种名为“死锁检测超时”的机制。当一个事务尝试获取锁时,如果等待锁的时间超过了一定的阈值(默认情况下,这个阈值是相当长的时间,通常为几秒钟甚至更长,具体时间可通过编译选项等方式调整),SQLite会假设可能发生了死锁。
- SQLite通过检查锁等待图来确定是否存在死锁。当事务请求锁时,SQLite会记录锁的依赖关系,形成一个锁等待图。如果在检查时发现图中存在环,就可以判定发生了死锁。
- 死锁解决
- 一旦检测到死锁,SQLite会选择一个事务作为牺牲品(通常是等待时间最长的事务),回滚该事务,并释放该事务持有的所有锁。这样可以打破死锁状态,使得其他事务能够继续执行。
- 应用程序可以捕获由于事务回滚而产生的错误(如
SQLITE_BUSY
或SQLITE_LOCKED
错误,具体取决于死锁情况和SQLite版本),并根据需要重新尝试事务,以确保数据操作的完整性。