golang常用库之-mgo.v2包、MongoDB官方go-mongo-driver包、七牛Qmgo包 | go操作mongodb、mongodb bson

golang常用库之-mgo.v2包、MongoDB官方go-mongo-driver包、七牛Qmgo包 | go操作mongodb、mongodb bson

一、【不推荐】mgo.v2包

  • mgo.v2包
    官网:http://labix.org/mgo
    引用包: gopkg.in/mgo.v2

mgo.v2包,已经跟不上mongo版本了,很早之前就停止维护了,后面会有更多的兼容性问题。不支持最新版本的mongo(5.x以上)

【推荐】github.com/vinllen/mgo

国人fork的一个mgo版本,github.com/vinllen/mgo 这个库支持新版本,而且不用改之前mgo代码。

该fork 进行了一些改进,添加了一些新功能,但大多用于改进性能和错误修复的变化。

使用mgo整理思路

  1. 创建 DialInfo 结构体实例,它包含与MongoDB群集建立会话的选项
  2. 调用 mgo.DialWithInfo 建立新会话,返回会话实例
  3. 在程序启动时,我创建了一个主 mgo.Session,然后,对于每个处理的请求,我复制主会话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 和核心结构体是 mgo.Session

// 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
}

mgo 创建索引(EnsureIndex方法)

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连接池设置

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 范围内实现复用,需要自行优化。

三、MongoDB官方 go-mongo-driver。

go-mongo-driver 功能抽象没有 mgo 那么高级,用起来很零碎。

四、【推荐】七牛Qmgo包

什么是qiniu/qmgo包

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

入库mongodb demo

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})

}

五、mongodb bson

什么是bson

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

Golang中struct tag bson

Go系列:结构体标签
参考URL: https://www.proyy.com/7005465902804123679.html

需求:mongdb golang编码中,根据struct tag 作为mongdb的文档的字段名,而不是结构体变量做为字段名,应该怎么做?

解决方案:
使用bson 结构体标签。
常用的结构体标签Key,指的是那些被一些常用的开源包声明使用的结构体标签键。在这里总结了一些,都是一些我们平时会用到的包,它们是:

  • json: 由encoding/json 包使用,详见json.Marshal()的使用方法和实现逻辑。
  • xml : 由encoding/xml包使用,详见xml.Marshal()。
  • bson: 由gobson包,和mongo-go包使用。
  • protobuf: 由github.com/golang/protobuf/proto 使用,在包文档中有详细说明。
  • yaml: 由gopkg.in/yaml.v2 包使用,详见yaml.Marshal()。
  • gorm: 由gorm.io/gorm包使用,示例可以在GORM的文档中找到。
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,我知道你的问题了。首先,使用beego框架和go-socket.io搭建聊天室需要以下步骤: 1. 安装beego和go-socket.io ```shell go get github.com/astaxie/beego go get github.com/googollee/go-socket.io ``` 2. 创建beego项目 ```shell bee new chatroom cd chatroom ``` 3. 在main.go中引入go-socket.io的并创建socket.io服务器 ```go package main import ( "github.com/astaxie/beego" "github.com/googollee/go-socket.io" ) func main() { server, err := socketio.NewServer(nil) if err != nil { beego.Error("Socket.IO server creation failed: ", err) return } // TODO: 后续代码 } ``` 4. 添加路由 ```go server.On("connection", func(so socketio.Socket) { beego.Info("New user connected.") // 处理用户连接事件 so.On("chat", func(msg string) { beego.Info("Message received: ", msg) // TODO: 处理消息 }) // 处理用户断开连接事件 so.On("disconnection", func() { beego.Info("User disconnected.") }) }) // 处理根路由 beego.Router("/", &controllers.MainController{}) // 处理socket.io路由 beego.Handler("/socket.io/", server) beego.Handler("/socket.io.js", http.FileServer(http.Dir("./node_modules/socket.io-client/dist/")).ServeHTTP) ``` 5. 在前端页面上添加socket.io客户端代码 ```html <script src="/socket.io.js"></script> <script> var socket = io.connect('http://localhost:8080'); socket.on('connect', function () { console.log('Connected to server.'); }); socket.on('chat', function (message) { console.log('Message received: ' + message); }); socket.on('disconnect', function () { console.log('Disconnected from server.'); }); </script> ``` 6. 处理聊天消息 ```go server.On("connection", func(so socketio.Socket) { beego.Info("New user connected.") // 处理用户连接事件 so.On("chat", func(msg string) { beego.Info("Message received: ", msg) // 广播消息给所有用户 server.BroadcastToAll("chat", msg) }) // 处理用户断开连接事件 so.On("disconnection", func() { beego.Info("User disconnected.") }) }) ``` 这样,你就可以使用beego框架和go-socket.io搭建一个简单的聊天室了。当然,以上代码只是一个简单的示例,你可以根据具体需求进行修改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

西京刀客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值