MongoDB事务在Python中生效的前提是连接副本集或分片集群并显式绑定同一session;单机部署、漏传session参数或跨实例操作会导致事务退化为普通操作。

MongoDB 事务在 Python 中能真正起作用,只有一条硬性前提:你连接的是副本集(replicaSet)或分片集群,且所有操作都显式绑定同一个 session。单机部署、漏传 session 参数、跨独立 mongod 实例——这三类情况会让事务静默退化为普通操作,表面成功,实则无原子性保障。
事务必须运行在 replicaSet 连接上
本地默认的 mongodb://localhost:27017 连接不支持事务,即使代码里写了 with_transaction,也会直接报错 CommandNotSupported: Transactions are not supported on standalone servers。
- 连接字符串必须包含
?replicaSet=rs0(rs0 替换为你实际的副本集名),例如:mongodb://host1:27017,host2:27017,host3:27017/?replicaSet=rs0 - 启动 MongoDB 时不能用
--dbpath单机模式,必须用--replSet rs0并执行rs.initiate() - PyMongo 会自动检测连接类型;如果连接成功但没带
replicaSet,client.start_session()仍能返回 session,但后续事务操作必然失败
所有操作必须显式传入 session 参数
updateOne、insert_one、find 这些方法默认不参与事务——除非你手动把 session 作为关键字参数传进去。漏传一个,整个事务就“破防”了。
- 错误写法:
collection.update_one({...}, {...})→ 游离于事务外 - 正确写法:
collection.update_one({...}, {...}, session=session) - 注意:
session是位置/关键字参数,不能放在**kwargs里被吞掉;也不能用session.bind(...)之类不存在的 API - 跨数据库操作同理:两个
db1.coll1和db2.coll2的操作,都要各自传session=session
优先用 session.with_transaction(),别手动管理 commit/abort
session.start_transaction() + 手动 commit_transaction()/abort_transaction() 容易出错:异常未捕获导致悬挂事务、重复 commit、忘记 abort 都可能引发数据异常。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
立即学习“Python免费学习笔记(深入)”;
-
session.with_transaction()是封装好的安全模式:传一个 async 函数(或普通函数),成功自动 commit,抛异常自动 abort - 它还会自动重试
TransientTransactionError(比如写冲突),而手动模式不会 - 唯一要注意:函数体内所有 DB 操作必须显式传
session,且不能有阻塞外部调用(如 HTTP 请求、sleep),否则会拖长事务时间,触发 60 秒默认超时
事务内禁止建库、建集合、建索引
事务不是万能的“黑盒”,MongoDB 明确限制了哪些命令能在事务中执行。试图在事务里调用 create_collection 或 create_index,会立刻报错 OperationNotSupportedInTransaction。
- 所有涉及的集合必须提前存在;事务只能做读写,不能做 DDL
- 不能用
dropDatabase、listCollections、aggregate(带某些 stage 如$out)等命令 - 如果业务需要“先建表再写入”,得拆成两步:先在事务外建好集合,再进事务做业务逻辑
最容易被忽略的一点是:事务的 ACID 保证依赖 w:majority 写关注和 readConcern: "majority"。如果只是加了 session 但没配这两个,主从切换时仍可能丢数据或读到脏数据——这不是事务本身的问题,而是部署配置没跟上。

















