【发布时间】:2021-03-18 17:14:29
【问题描述】:
我知道函数的名称似乎是不言自明的,但是,在研究了很长一段时间后,我在 clientSession 中的任何地方都找不到事务号。 是内部号码吗?有可能得到吗?
【问题讨论】:
标签: node.js mongodb apollo-datasource
我知道函数的名称似乎是不言自明的,但是,在研究了很长一段时间后,我在 clientSession 中的任何地方都找不到事务号。 是内部号码吗?有可能得到吗?
【问题讨论】:
标签: node.js mongodb apollo-datasource
mongodb 使用事务编号来跟踪每个会话的每个事务的操作(读/写)。会话可以通过调用 startSession() 显式启动,也可以在您创建与数据库服务器的 mongodb 连接时隐式启动。
当您启动会话时,通过调用client.startSession() method,它将创建一个新的ClientSession。这会将已创建的服务器会话池作为其构造函数参数之一。 (See) 这些服务器会话有一个名为 txnNumber 的属性,它被初始化为 0。(Init) 因此,每当您通过调用 startTransaction() 启动事务时,客户端会话对象都会在内部调用 incrementTransactionNumber() 以增加 txnNumber in服务器会话。并且所有后续操作都将使用相同的txnNumber,直到您调用commitTransaction() 或abortTransaction() 方法。在 clientSession 中的任何地方都找不到它的原因是,它是 serverSession 而不是 clientSession 的属性。
class ServerSession {
constructor() {
this.id = { id: new Binary(uuidV4(), Binary.SUBTYPE_UUID) };
this.lastUse = now();
this.txnNumber = 0;
this.isDirty = false;
}
因此,每当您尝试向数据库发送命令(读/写)时,此txnNumber 将与它一起发送。 (Assign transaction number to command)
这是为了跟踪每个会话属于给定事务的数据库操作。 (在每个会话中唯一标识每个事务的事务操作历史记录。)
在这种情况下,如果该命令不属于事务并且它是启用了 retryWrites 的写入操作,则每次向数据库发出新命令时都会调用它。因此,只要每个新的写操作不属于startTransaction() 的显式启动事务,它就会有新的事务编号。但在这种情况下,txnNumber 也会与每个命令一起发送。
const willRetryWrite =
topology.s.options.retryWrites === true &&
session &&
!inTransaction &&
supportsRetryableWrites(server) &&
operation.canRetryWrite;
if (
operation.hasAspect(Aspect.RETRYABLE) &&
((operation.hasAspect(Aspect.READ_OPERATION) && willRetryRead) ||
(operation.hasAspect(Aspect.WRITE_OPERATION) && willRetryWrite))
) {
if (operation.hasAspect(Aspect.WRITE_OPERATION) && willRetryWrite) {
operation.options.willRetryWrite = true;
session.incrementTransactionNumber();
}
operation.execute(server, callbackWithRetry);
return;
}
operation.execute(server, callback);
也请阅读this article。是的,如果您需要,您可以通过txnNumber 属性、clientSession.serverSession.txnNumber 获取任何会话的事务编号。
【讨论】: