面试题答案
一键面试1. MongoDB并发控制机制概述
MongoDB使用多文档事务来处理高并发场景下的数据一致性问题。其并发控制主要依赖于两阶段锁(2PL)协议。在事务开始时,MongoDB会获取锁,直到事务提交或回滚时才释放锁。
2. 事务隔离级别及实现方式
- 读未提交(Read Uncommitted):
- 实现:在MongoDB中,默认情况下,读取操作是“读已提交”。但通过一些配置(在特定驱动下)可以模拟读未提交,例如在某些场景下禁用文档级别的锁定,这样读取操作可能会看到未提交的数据。但这在MongoDB正常事务处理中不是标准做法,因为MongoDB设计初衷是为了数据一致性,读未提交可能导致脏读问题。
- 举例:假设事务T1更新了文档A的值但未提交,在模拟读未提交场景下,事务T2可以读取到文档A更新后但未提交的值。如果T1最终回滚,T2读取到的值就是无效的(脏数据)。
- 读已提交(Read Committed):
- 实现:MongoDB默认支持读已提交隔离级别。当一个事务读取数据时,它只能看到已经提交的修改。在读取文档时,MongoDB会检查文档的版本号(如果存在)或者使用锁机制来确保读取到的是已提交的数据。
- 举例:事务T1更新文档A的值并提交,事务T2在T1提交后读取文档A,此时T2读取到的是T1提交后的新值,而不是更新前的值。如果T1未提交,T2读取到的还是旧值。
- 可重复读(Repeatable Read):
- 实现:MongoDB通过在事务开始时创建一个一致性快照来实现可重复读。在整个事务期间,所有读取操作都基于这个快照,确保在事务内多次读取相同数据时得到一致的结果,不受其他并发事务提交的影响。
- 举例:事务T1在开始时读取文档A的值为10。在事务执行过程中,事务T2更新并提交了文档A的值为20。但由于T1基于自己开始时的快照,当T1再次读取文档A时,仍然会读到值10,而不是T2提交后的20。
- 串行化(Serializable):
- 实现:MongoDB通过严格的两阶段锁协议来模拟串行化隔离级别。在事务执行期间,MongoDB会获取所有涉及文档的锁,并且在事务提交或回滚前不会释放锁。这确保了事务之间串行执行,避免了并发问题。
- 举例:假设有事务T1和T2都要更新文档A。T1先开始并获取了文档A的锁,T2尝试更新文档A时会被阻塞,直到T1提交或回滚释放锁。这样就保证了事务像串行执行一样,避免了并发更新可能导致的数据不一致。