mongoose事务中save和find的session有什么区别?

4
这两种方法有什么区别吗?
const something = Model.findById(id).
something.save({ session })

const something = Model.findById(id).session(({ session })
something.save() 

在测试时,功能是相同的。在mongoose事务中使用session的正确方式是什么?


你并没有修改文档的任何内容,为什么要保存呢? - OneCricketeer
1个回答

7

首先在事务处理中,你需要使用 async/await

const something = await Model.findById(id).
await something.save({ session })

但是使用事务可以在隔离的情况下执行多个操作,如果其中一个操作失败,可以可能地撤销所有操作,事务的主要目标是在MongoDB中让你以隔离的方式更新多个文档

但在您的示例中,您只更新了一个集合,不需要使用事务。我们来看下面的例子,这个create()是因为session而成为事务的一部分,而事务是在隔离环境中执行的,所以除非你将session传递给findOne(),否则在提交事务之前你不会看到结果。因此,findOne的结果是null

const session = await db.startSession();
session.startTransaction();
await Model.create([{ name: 'Test' }], { session: session });
let result = await Model.findOne({ name: 'Test' });//without session
session.endSession();

在以下示例中,这个findOne()将返回结果,因为传递了session,这意味着这个findOne()将作为事务的一部分运行。
const session = await db.startSession();
session.startTransaction();
await Model.create([{ name: 'Test' }], { session: session });
let result = await Model.findOne({ name: 'Test' }).session(session);
session.endSession();

如果您使用会话从findOne()或find()获取一个Mongoose文档,则该文档将保留对会话的引用,并在save()中使用该会话,在以下示例中,由于save()是未提交事务的一部分,因此不会找到result,但firstResult不是Null。
const session = await db.startSession();
session.startTransaction();
await Model.create({ name: 'Test' });
const something  = await Model.findOne({ name: 'Test' }).session(session);
something.name = 'firstTest';
await something.save();

let result = await Model.findOne({ name: 'firstTest' }); //Is Null
await session.commitTransaction();
session.endSession();

firstReuslt = await Model.findOne({ name: 'firstTest' });//Is Not Null

如果您想要更新两个集合,可以使用以下代码:save({session:sess}),但如果您只想更新一个集合,则不需要使用该代码,因为:如果使用会话从findOne()或find()获取Mongoose文档,则文档将保留对该会话的引用,并使用该会话进行save()
const sess = await mongoose.startSession();
sess.startTransaction();
await first.save({ session: sess }); 
await second.save({ session: sess });
await sess.commitTransaction();

我理解代码的最后一部分是在查找时增加session,这个解释很好。您能否解释一下如果我在.save()中添加session会发生什么? - keisaac
我更新了我的答案,希望你的问题得到解决。 - Mohammad Yaser Ahmadi
所以基本上当我更新两个或更多集合时,我会在save()上放置session对吧?但是当我在查找对象时放置session而在save时不放置session。它具有相同的功能,如果我中止它,它也会恢复。 - keisaac
如果您想在实际项目中查找一个文档并将其保存(save()),则无需使用session,只需将findsave放入try/catch中即可。当您想要更新两个或更多的集合时,请使用session。 - Mohammad Yaser Ahmadi
这些示例很好,但是错过了重点。无论如何,您都不应该使用findOnesave。对于原子操作,请使用updateOne。否则,删除操作可能会在查找之后但保存之前由其他客户端发生,然后您将重新插入本应已被删除的内容。 - OneCricketeer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接