golang中使用 mongoDB ObjectId

ObjectId

mongoDB中存储的文档必须有一个"_id"键,这个键的值可以是任何类型的,默认是ObjectId对象。通常也不建议存成其他类型,例如字符串,原因有以下三个方面:

  1. 不方便查询(字符串和OjbectId不能相互匹配);
  2. OjbectId含有有用的信息,绝大多数驱动都有方法从OjbectId中获取文档的创建日期等信息;
  3. 字符串表示的OjbectId会多占两倍的磁盘空间。

在一个集合里面,每个文档都有唯一的"_id"值,来确保集合里面每个文档都能被唯一标识。那么你可能会问,既然ObjectId的作用是用来标识文档,那为什么不用普通递增id呢?后文有解释。
这就需要了解MongoDB的特点,MongoDB是一个基于分布式文件存储的数据库。因此在高并发的场景下,自增id与MongoDB的设计背道而驰。在分布式环境中,自增id要保证正确递增必然会影响效率,因此MongoDB采用ObjectId作为对象标识。ObjectId是bson(binary json)类型的数据,由12位值组成:

  • 前4个字节表示时间戳,是文档创建时的时间,它是递增的,可以保证ObjectId总体递增的顺序。
    但是上面的递增不是绝对的,因为这个时间只是精确到秒,而同一台机器同一秒内生成的ObjectId还会因pid不同而不同,pid小的ObjectId始终排在pid大的那个前面。
  • 接着3位是机器识别码
    也就是在同一台机器中,每次生成ObjectId中,这三个字节总相等
  • 紧接2位着是进程id的值
  • 最后3位是随机值
    在机器、进程都确定的情况下,某一秒最多有2^24-1个对象,也就是16777215,从目前机器的性能来看,很难超过这个限制。

了解了这些,其实你自己就可以尝试动手写一个ObjectId生成器。下面看mgo包对其的支持。

ObjectId的生成

package main

import (
    "gopkg.in/mgo.v2/bson"
    "fmt"
)

func main(){
    //生成一个新的ObjectId值
    id := bson.NewObjectId()
	fmt.Println(id)
    //从ObjectId中获取时间戳
	idTime := id.Time()
	fmt.Println(idTime)
    //从ObjectId中获取机器码
	idMac := id.Machine()
	fmt.Println(idMac)
    //从ObjectId中获取进程id
	idPid := id.Pid()
	fmt.Println(idPid)
    //从OjbectId中获取随机数
	idCount := id.Counter()
	fmt.Println(idCount)
}

执行后的结果如下所示:

ObjectIdHex("5b0c01a2f2fad1839452c0e7")
2018-05-28 21:18:26 +0800 CST
[242 250 209]
33684
5423335

参考文章

  1. mongoDB修改"_id"的objectID到普通递增id为什么不好
  2. 关于ObjectId的问题总结
相关推荐
©️2020 CSDN 皮肤主题: 酷酷鲨 设计师:CSDN官方博客 返回首页