ObjectId是一个24位的字符串,实际是由一组十六进制的字符构成,共12个字节。(1个字节8位能表示2个十六进制数,12个字节能表示24个十六进制数)。
ObjectId 是一个12字节 BSON 类型数据,有以下格式:
- 前4个字节表示时间戳(精确到秒的时间戳)
- 接下来的3个字节是机器标识码
- 紧接的两个字节由进程id组成(PID)
- 最后三个字节是随机数。
我们的SpringBoot、SpringMVC程序往Mongodb插入一个文件时,这个ObjectId不是Mongodb生成的,而是由我们的应用程序生成的保存到Mongodb数据库。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
spring-boot-starter-data-mongodb实现了ObjectId类,里面实现了ObjectId的生成。
首先看一下ObjectId有一个静态代码块
0x01000000 ---> 0000 0001 0000 0000 0000 0000 0000 0000 ---> 2^24
0x00008000 ---> 0000 0000 0000 0000 1000 0000 0000 0000 ---> 2^15
RANDOM_VALUE1代表了3个字节的机器标识符
RANDOM_VALUE2代表了2个字节的进程id(两个字节的最大值为2^16,但是操作系统的pid范围的最大值默认是2^15,所以随机生成数最大值的范围到2^15就够了)
ObjectId类里还有一个重要的变量,NEXT_COUNTER,它是一个静态线程安全的Integer(在同一个java进程中,在一秒内,多个线程同时生成ObjectId,最后每个ObjectId的最后三个字节一定是不一样的),最后三个字节的随机数将由它来生成,初始值是随机的,每使用一次就自增1,使用的时候会跟0x00ffffff相与,保证数值在三个字节以内。
private static final AtomicInteger NEXT_COUNTER = new AtomicInteger(new SecureRandom().nextInt());