
Mgo 库本身不会缓存或复用传入 mgo.Dial() 的连接字符串;所谓“仍连旧库”实为代码中其他位置(如 session.DB("old-name"))硬编码了旧数据库名所致,需全面检查数据库名称的显式引用点。
mgo 库本身不会缓存或复用传入 `mgo.dial()` 的连接字符串;所谓“仍连旧库”实为代码中其他位置(如 `session.db("old-name")`)硬编码了旧数据库名所致,需全面检查数据库名称的显式引用点。
在使用 mgo(v2)连接 MongoDB 时,一个常见误解是认为 mgo.Dial() 会“记住”或缓存连接字符串——实际上,mgo 完全不缓存连接参数。每次调用 mgo.Dial(url) 都会解析并建立一条全新的连接(底层基于标准 net.Dial),连接字符串仅用于初始化会话,不会被持久化、复用或跨调用影响。
真正导致你遇到 not authorized for query on my-old-db-name 错误的原因,几乎可以确定是:你在后续操作中显式指定了旧的数据库名,而非连接字符串本身生效问题。
关键点在于区分两个概念:
- ✅ mgo.Dial("mongodb://.../db-name") 中的 /db-name 仅作为默认数据库名(default database),用于认证和初始化会话,但它 不强制限定 后续所有操作的数据库;
- ❌ session.DB("my-old-db-name") 才是实际决定查询、写入目标数据库的权威调用——它会覆盖连接字符串中的默认值,并且完全独立于 Dial 参数。
例如,以下代码看似更新了连接串,但依然访问旧库:
// 正确更新了连接字符串(指向新库)
session, err := mgo.Dial("mongodb://u:p@dogen.mongohq.com:10048/new-db-name")
if err != nil {
log.Fatal(err)
}
defer session.Close()
// ⚠️ 危险!这里仍显式使用旧库名 —— 这才是错误根源
db := session.DB("my-old-db-name") // ← 即使 Dial 里写了 new-db-name,此处仍连 old
c := db.C("users")
err = c.Find(nil).All(&results) // → 报错:not authorized for query on my-old-db-name✅ 正确做法是统一数据库名引用:
// 方案一:Dial 时指定默认库 + 后续统一用 session.DB("new-db-name")
session, _ := mgo.Dial("mongodb://u:p@dogen.mongohq.com:10048/new-db-name")
db := session.DB("new-db-name") // 显式、一致
// 方案二(更推荐):Dial 不带库名(仅认证),所有 DB 名在业务逻辑中动态/集中管理
session, _ := mgo.Dial("mongodb://u:p@dogen.mongohq.com:10048/") // 末尾无 /db
db := session.DB(os.Getenv("MONGO_DB_NAME")) // 从环境变量注入,便于配置管理? 注意事项与最佳实践:
- 永远不要在多处硬编码数据库名(如 "my-old-db-name" 字符串散落在多个文件中);
- 使用常量、配置项或环境变量统一管理数据库名,确保变更一处即全局生效;
- mgo.Dial() 的 URL 中 /db-name 仅影响初始认证上下文(例如 admin 或 local 等系统库认证),对业务集合操作无约束力;
- 若使用连接池(如 session.Copy()),务必注意 Copy() 后仍需调用 .DB("xxx") 指定目标库——复制的是会话状态,不是数据库绑定;
- mgo 已归档(官方已标记为 unmaintained),生产环境建议迁移到官方 mongo-go-driver,其设计更清晰(如 client.Database("name") 显式分离连接与库作用域)。
简言之:不是 Mgo 缓存了连接串,而是你的代码“悄悄”记住了旧库名。排查时请全局搜索 "my-old-db-name" 字符串,尤其是 session.DB(...) 调用点——这才是真正的症结所在。










