事务中readpreference必须为primary,这是mongodb协议级硬性限制,所有驱动均强制覆盖或报错,因事务需保证因果一致性与原子性,跨分片及读写一致性要求所有操作必须在primary节点执行。

事务里不能配 readPreference,MongoDB 会强制覆盖或报错——这不是配置问题,是协议级硬性限制。
事务必须用 primary,连设都不让设
所有事务内的读操作(find()、countDocuments() 等)自动绑定到当前 primary,驱动层根本不会接受你传的 readPreference 参数:
-
startTransaction({ readPreference: 'secondary' })—— Node.js 驱动直接忽略该字段,不报错但也不生效 -
session.getDatabase('db').getCollection('coll').find().readPref('secondary')—— 在 mongosh 或任何驱动中执行,立刻抛出错误:"Read preference in a transaction must be primary" - 连接字符串里带
?readPreference=secondary,进事务后也完全失效,服务器端校验时直接拒绝非primary的请求
为什么非得是 primary?不是“推荐”,是因果一致性的底线
事务要求所有读写在同一个节点上原子执行,否则会出现以下不可控情况:
- 你在
secondary上读到旧数据,再在primary上写新值,事务的“读已提交”语义就崩了 - 跨分片事务时,每个分片的
primary必须全部可用;如果允许读secondary,就无法保证各分片间操作的顺序和可见性 - 即使你绕过驱动拼 raw command 发过去,mongod 也会在解析阶段校验并返回
InvalidOptions错误
想读从节点?别塞进事务里,拆 session
业务上常见的“写主库 + 读从库”需求,必须用两个独立 session 实现:
- 一个带事务的 session:只做写操作(
updateOne、insertOne),自动走primary,不用管readPreference - 另一个普通 session:显式设
readPreference: 'secondary',只做查询(find、aggregate),和事务 session 完全隔离 - PHP / C / Node.js 驱动都一样:事务选项里压根没有
readPreference字段,startTransaction()只收readConcern和writeConcern
真正容易被忽略的是:事务的隔离性不靠参数控制,而靠节点一致性保障。你传什么、怎么设,最终都由服务器强制归一到 primary——这不是配置疏漏,是 ACID 的底层契约。











