如何在Atlas Functions中读取事务内未提交的更新?
问题根源
MongoDB多文档事务默认采用快照隔离级别(readConcern: "snapshot"),事务启动后,所有读操作都会基于事务开始时的数据快照执行。哪怕你在事务内完成了更新操作,后续的读操作依然只会看到事务启动时的旧数据,无法读取到本次事务内的修改结果。
解决方案
要在事务内读取到自身的更新,需要在读取操作中显式指定readConcern: { level: "local" },同时确保读操作绑定同一个事务session。
修改后的代码
exports = async function({ query, headers, body}, response) { const collection = context.services.get("mongodb-atlas").db("zakhar").collection("w"); // clean up and insert init data await collection.deleteMany({}); await collection.insertOne({"name": 1, "category": "toy"}); await collection.insertOne({"name": 2, "category": "toy"}); await collection.insertOne({"name": 3, "category": "game"}); await collection.insertOne({"name": 4, "category": "game"}); const session = context.services.get("mongodb-atlas").startSession(); const transactionOptions = { readPreference: "primary", readConcern: { level: "local" }, writeConcern: { w: "majority" } }; try { await session.withTransaction(async () => { await updateStatus(session); }, transactionOptions); return 'ok'; } catch (err) { await session.abortTransaction(); throw err; } finally { await session.endSession(); } }; async function updateStatus(session){ const collection = context.services.get("mongodb-atlas").db("zakhar").collection("w"); const countBeforeUpdate = await collection.find( {"category": "toy"}, { readConcern: { level: "local" } }, { session } ).toArray(); console.log("countBeforeUpdate: " + countBeforeUpdate.length); const query = {"name": 1}; const update = {"$set": {"category": "game"}}; await collection.updateOne(query, update, { session }) .then(result => { const { matchedCount, modifiedCount } = result; console.log("matchedCount: " + matchedCount); console.log("modifiedCount: " + modifiedCount); }); const countAfterUpdate = await collection.find( {"category": "toy"}, { readConcern: { level: "local" } }, { session } ).toArray(); console.log("countAfterUpdate: " + countAfterUpdate.length); }
说明
readConcern: "local"允许读取到同一个事务内已完成的写操作结果,打破了快照隔离的限制,适用于需要在事务内验证修改结果的场景。- 事务级别的
readConcern设置是默认值,若要覆盖单个读操作的级别,必须在对应读操作上显式声明。
修改后执行,countAfterUpdate会输出1,符合预期。
内容的提问来源于stack exchange,提问作者Zakhar
相关产品推荐
相关产品推荐

