mgo.v2包,已经跟不上mongo版本了,很早之前就停止维护了,后面会有更多的兼容性问题。不支持最新版本的mongo(5.x以上)!
国人fork的一个mgo版本,github.com/vinllen/mgo 这个库支持新版本,而且不用改之前mgo代码。
该fork 进行了一些改进,添加了一些新功能,但大多用于改进性能和错误修复的变化。
session.Copy()
并在完成后关闭它。伪代码示例:
var dialInfo *mgo.DialInfo
//dialInfo 实例各种配置赋值
dialInfo.Timeout = time.Second * 5
m.dbSession, err = mgo.DialWithInfo(dialInfo)
sess := m.dbSession.Copy()
defer sess.Close()
err = m.dbSession.DB("").C(colName).Create(&mgo.CollectionInfo{Capped: true, MaxBytes: colCapMaxSizeBytes})
注意:如果Capped是true,那么当collection 满了。必须设置MaxBytes定义集合wraps 的大小。
MaxDocs是可选的,可以定义wraps的文档数,但仍需要设置MaxBytes。
做插入文档操作,使用的是Insert方法,如下:
伪代码
sess := m.dbSession.Copy()
defer sess.Close()
sess.DB("").C(collectionName).Insert(dataSet...)
// Insert 集合中插入一个或多个文档
func (c *Collection) Insert(docs …interface{}) error {
// mgo.v3: Drop Strong mode, suffix all modes with "Mode".
// When changing the Session type, check if newSession and copySession
// need to be updated too.
// Session represents a communication session with the database.
//
// All Session methods are concurrency-safe and may be called from multiple
// goroutines. In all session modes but Eventual, using the session from
// multiple goroutines will cause them to share the same underlying socket.
// See the documentation on Session.SetMode for more details.
type Session struct {
defaultdb string
sourcedb string
syncTimeout time.Duration
sockTimeout time.Duration
poolLimit int
poolTimeout time.Duration
consistency Mode
creds []Credential
dialCred *Credential
safeOp *queryOp
mgoCluster *mongoCluster
slaveSocket *mongoSocket
masterSocket *mongoSocket
m sync.RWMutex
queryConfig query
bypassValidation bool
slaveOk bool
}
Mongodb里面,如果不添加索引,对Mongodb数据表进行查询操作的时候,需要把数据都加载到内存。当数据的数量达到几十万乃至上百万的时候,这样的加载过程会对系统造成较大的冲击,并影响到其他请求的处理过程。
用户表当前的记录数量已经达到45万,每次都加载这么多数据,查询起来肯定是非常慢的。建立索引以后对索引字段进行查询时,仅会加载索引数据,能极大地提高查询速度。
引用mgo,代码中调用
err = c.EnsureIndex(idIndex)
if err != nil {
return errors.Wrap(err, "failed to ensures an index with the given key exists")
}
网上代码demo:
package main
import (
"fmt"
"log"
"time"
"gopkg.in/mgo.v2"
)
const (
MongoDBHosts = "IP:PORT" //mongodb 地址端口
AuthDatabase = "dbname" //autn 库
AuthUserName = "username" //auth 用户名
AuthPassword = "password" // auth 密码
MaxCon = 300 //连接池socket设置
)
func main() {
mongoDBDialInfo := &mgo.DialInfo{
Addrs: []string{MongoDBHosts},
Timeout: 60 * time.Second,
Database: AuthDatabase,
Username: AuthUserName,
Password: AuthPassword,
}
session, err := mgo.DialWithInfo(mongoDBDialInfo)
if err != nil {
log.Fatalf("CreateSession failed:%\n", err)
}
//建立collection
coll := session.DB("test").C("user")
/*
EnsureIndexKey ensures an index with the given key exists, creating it if necessary
*/
//索引存在则不进行操作,不存在自动创建
// err = coll.EnsureIndexKey("a", "b")
//fmt.Println("err-----------------:",err)
//查询所有的已存在索引
// indexs, err := coll.Indexes()
// fmt.Println("err-----------------:", err)
// fmt.Println("indexs--------------:", indexs)
//删除索引,成功返回nil,如果不存在则返回对应的具体信息
// err = coll.DropIndex("a", "b")
// fmt.Println("err-----------------:", err)
//设置连接池的大小,默认4096可自定义修改根据需求
session.SetPoolLimit(MaxCon)
defer session.Close()
}
golang mgo的mongo连接池设置:必须手动加上maxPoolSize
参考URL: https://www.cnblogs.com/shenguanpu/p/5318727.html
mgo 的 session 与连接池(精)
参考URL: https://www.fecmall.com/topic/581
golang main入口启动时,我们会创建一个全局session,然后每次使用时clone session的信息和连接,用于本次请求,使用后调用session.Close() 释放连接。
session的拷贝与并发
为什么要在每次使用时都Copy,而不是直接使用Dial生成的session实例呢?个人认为,这与mgo.Session的Socket缓存机制有关。来看Session的核心数据结构。
mgo连接池是自带的,你只需要使用session.Copy()拿到一个复制的session,用完之后session.Close()即可。
Clone的方法注释里说明会重用原始session的socket连接,但是并发请求一大,其他协程来不及释放连接,当前协程会怎么办?
不断的创建连接
netstat -nat|grep -i 27017|wc -l
如果每个session 不调用close,会达到恐怖的4096,并堵死其他请求,所以clone或copy session时一定要defer close掉。
启用maxPoolLimit 参数则会限制总连接大小,连接到限制则当前协程会sleep等待 直到可以创建连接
连接池设置方法:
1、配置中 增加
2、代码中 :
dao.GlobalMgoSession.SetPoolLimit(10)
再做压测:
$ netstat -nat|grep -i 27017|wc -l
15
mgo底层socket连接池只在maxPooMaxLimit 范围内实现复用,需要自行优化。
go-mongo-driver 功能抽象没有 mgo 那么高级,用起来很零碎。
github: https://github.com/qiniu/qmgo
七牛研发团队开源Go语言的MongoDB driver Qmgo。
它基于MongoDB官方 mongodb/mongo-go-driver 实现,但是有着更好的易用性,设计上参考了老牌的driver Mgo: go-mgo/mgo(比如Mgo的链式调用)。
相对于其他库,我发现这个库更新算是比较频繁,而且是以公司名义开源,可以试试~
示例查看官方demo即可: https://github.com/qiniu/qmgo/blob/master/README_ZH.md
package main
import (
"context"
"fmt"
"github.com/qiniu/qmgo"
)
type UserInfo struct {
Name string `bson:"name"`
Age uint16 `bson:"age"`
Weight uint32 `bson:"weight"`
}
func main() {
ctx := context.Background()
// Database:库名 Coll:集合名
cli, err := qmgo.Open(ctx, &qmgo.Config{Uri: "mongodb://127.0.0.1:27017", Database: "mongo_1", Coll: "collection_1"})
defer func() {
if err = cli.Close(ctx); err != nil {
panic(err)
}
}()
cli.EnsureIndexes(ctx, []string{}, []string{"age", "name,weight"})
var userInfo = UserInfo{
Name: "xm",
Age: 7,
Weight: 40,
}
// insert one document
result, err := cli.InsertOne(ctx, userInfo)
fmt.Println("result", result)
// find one document
//one := UserInfo{}
//err = cli.Find(ctx, bson.M{"name": userInfo.Name}).One(&one)
//err = cli.Remove(ctx, bson.M{"age": 7})
}
BSON( Binary Serialized Document Format) 是一种二进制形式的存储格式,采用了类似于 C 语言结构体的名称、对表示方法,支持内嵌的文档对象和数组对象,具有轻量性、可遍历性、高效性的特点,可以有效描述非结构化数据和结构化数据。
BSON是一种类json的一种二进制形式的存储格式,简称Binary JSON,它和JSON一样,支持内嵌的文档对象和数组对象,但是BSON有JSON没有的一些数据类型,如Date和BinData类型。
BSON可以做为网络数据交换的一种存储形式,这个有点类似于Google的Protocol Buffer,但是BSON是一种schema-less的存储形式,它的优点是灵活性高,但它的缺点是空间利用率不是很理想。
MongoDB使用了BSON这种结构来存储数据和网络数据交换。把这种格式转化成一文档这个概念(Document),因为BSON是schema-free的,所以在MongoDB中所对应的文档也有这个特征,这里的一个Document也可以理解成关系数据库中的一条记录(Record),只是这里的Document的变化更丰富一些,如Document可以嵌套。
BSON这种格式是专门为MongoDB而开发的,类似json的一种二进制格式。这种格式不一定比json存储的文件小,其优点是解释快。
总结: BSON是一种二进制序列化格式,用于在MongoDB中存储文档和进行远程过程调用。 有关BSON规范请访问 bsonspec.org
Go系列:结构体标签
参考URL: https://www.proyy.com/7005465902804123679.html
需求:mongdb golang编码中,根据struct tag 作为mongdb的文档的字段名,而不是结构体变量做为字段名,应该怎么做?
解决方案:
使用bson 结构体标签。
常用的结构体标签Key,指的是那些被一些常用的开源包声明使用的结构体标签键。在这里总结了一些,都是一些我们平时会用到的包,它们是: