mongo.Connect 默认不自动重连,超时后直接报错;需显式配置 ?retryWrites=true 才对单文档写操作(如 updateOne)启用最多1次自动重试,且仅在 MongoDB 4.0+ 副本集/分片集群及兼容驱动下生效。

mongo.Connect 默认不自动重连,超时后直接报错,不是“连不上就等一会儿”——这是新手最常误判的一点。
连接字符串里别漏掉 /?retryWrites=true
不加这个参数,mongo.Connect 建立的客户端在写操作失败时不会自动重试,尤其在副本集或分片集群中容易触发 write concern error 或 context deadline exceeded。官方驱动从 v1.4 起默认要求显式声明重试策略:
-
mongodb://localhost:27017/?retryWrites=true是最小安全配置 - 若用副本集,必须补全所有节点并加
&replicaSet=rs0,例如:mongodb://node1:27017,node2:27017/?replicaSet=rs0&retryWrites=true - 生产环境建议加上
&maxPoolSize=100&minPoolSize=5,避免短连接风暴打爆 MongoDB 连接数
context.WithTimeout 的时间得比 mongo.Connect 实际耗时长
常见错误是设了 5 秒超时,但网络抖动或 DNS 解析慢导致连接卡在 6 秒——结果 mongo.Connect 直接返回 context deadline exceeded,而你根本没机会看到底层真实的连接拒绝原因(比如认证失败、端口不通)。
- 本地开发用
10 * time.Second足够;CI/CD 环境建议设为30 * time.Second - 务必在
defer cancel()后立刻调用client.Ping,否则可能拿到一个“已连上但实际不可用”的 client 实例 - 如果 Ping 失败,错误信息里带
server selection timeout,说明是路由或拓扑发现失败,不是账号密码错
别用 context.TODO() 做数据库操作上下文
context.TODO() 没有超时控制,一旦 MongoDB 响应延迟(比如聚合查询卡住、索引缺失导致全表扫描),整个 goroutine 就会无限挂起,最终拖垮服务。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
立即学习“go语言免费学习笔记(深入)”;
- 所有
InsertOne、Find、UpdateOne必须传带超时的 context,例如:ctx, _ := context.WithTimeout(context.Background(), 5*time.Second) - 对读多写少场景,可区分设置:读操作用 3 秒,写操作用 10 秒(因要等写确认)
- 注意
mongo.Collection.Find返回的*mongo.Cursor也需在 defer 中Close,否则游标泄漏,MongoDB 内存持续上涨
bson.M 和 bson.D 别混用在同一个查询条件里
虽然两者都能构造查询参数,但语义不同:bson.M 是无序 map,bson.D 是有序 slice。当条件含 $or、$and 或需要字段顺序敏感的操作(如 $sort 配合 $group)时,bson.M 可能导致意外结果。
- 简单等值查询用
bson.M{"name": "alice", "age": 30}没问题 - 涉及逻辑操作符或排序时,强制用
bson.D{{"name", "alice"}, {"age", 30}} - 嵌套结构如
$or: [{a: 1}, {b: 2}],外层用bson.M,内层数组元素必须是bson.D,否则驱动解析失败
真正容易被忽略的是:MongoDB 驱动的 mongo.Client 实例是线程安全的,可以全局复用,但很多人在每个 HTTP handler 里都重新 mongo.Connect,既浪费资源又掩盖了连接池配置问题。

















