面试题答案
一键面试并发控制确保事务隔离性
- 多文档事务:MongoDB 4.0 及以上版本支持多文档事务。它采用两阶段锁(2PL)机制来确保事务的隔离性。在事务开始时,并不会立即获取所有需要的锁,而是在执行过程中,当访问到某个文档时,才获取相应的锁。
- 锁粒度:MongoDB 的锁粒度相对较粗,主要是数据库级别的锁。在一个事务中,如果对多个文档进行操作,这些操作会在同一个数据库级别锁的保护下进行,以防止其他并发事务对相同数据库中的文档进行冲突操作。
- 隔离级别:MongoDB 的多文档事务默认提供“读已提交”隔离级别。在这种隔离级别下,一个事务只能读取已经提交的其他事务的修改。这意味着在事务执行过程中,对数据的读取不会看到未提交的修改,从而保证了事务之间的数据隔离。
事务生命周期内资源分配与管理
- 锁的分配:
- 开始阶段:事务开始时,MongoDB 会在内存中记录事务的状态和相关信息。随着事务对文档的操作,逐步分配锁。例如,当事务第一次尝试读取或写入某个文档时,会获取该文档所在数据库的锁。
- 升级锁:如果事务最初以共享锁(读锁)访问文档,之后又需要对该文档进行写入操作,锁会升级为排他锁(写锁)。这种升级操作会阻塞其他事务对该文档的读或写操作,直到当前事务完成或释放锁。
- 锁的管理:
- 持有锁:在整个事务生命周期内,MongoDB 会一直持有已获取的锁,以确保事务操作的原子性和隔离性。只有当事务提交或回滚时,才会释放所有持有的锁。
- 锁队列:当多个事务竞争同一资源(如数据库锁)时,MongoDB 会使用队列来管理等待获取锁的事务。先请求锁的事务会在队列中排在前面,按照顺序获取锁。
死锁检测与处理
- 死锁检测:MongoDB 采用等待图(Wait - for Graph,WFG)算法来检测死锁。等待图记录了事务之间的锁依赖关系,即哪些事务在等待其他事务释放锁。MongoDB 的后台线程会定期检查等待图,如果发现图中存在环,就意味着发生了死锁。
- 死锁处理:一旦检测到死锁,MongoDB 会选择一个事务作为“牺牲者”(通常选择事务开销最小的,如执行操作最少的事务)。然后,终止这个“牺牲者”事务,并回滚其所有操作,释放它持有的所有锁。这样,其他事务就可以继续执行,从而打破死锁状态。同时,应用程序会收到相应的错误信息,提示事务因死锁被终止,应用程序可以选择重新执行该事务。