ObjectId的选择

创建MongoDB文档时,如果没有赋值ID,系统会自动帮你创建一个,通常会在客户端由驱动程序完成。得到的ObjectId类似于这种

 

ObjectId使用12字节的存储空间,每个字节两位十六进制数字,是一个24位的字符串。其含义分别代表时间戳、机器码、PID、计数器。时间戳是文档创建时的时间,只是从十进制转化成了十六进制。机器码是生成文档主机的ID,为了区分多主机而生成的。PID则是区分同主机下不同mongoDB进程产生的,同样防止冲突。前面的9个字节是保证了一秒内不同机器不同进程生成ObjectId不冲突,最后的3个字节是一个自动增加的计数器,用来确保在同一秒内产生的ObjectId也不会冲突,允许256的3次方等于16777216条记录的唯一性。

显然系统生成的ObjectID已经很严谨了,但是在选择系统创建还是程序创建id上,经过网上查找的一些资料,得到的结论是尽量采用程序创建的方式,速度、可读性、可维护性都要强于系统创建。

虽然ObjectId 设计成轻量型的,易于生成,但是毕竟生成的时候还是产生开销。在客户端生成体现了MongoDB 的设计理念:能从服务器端转移到驱动程序来做的事,就尽量转移。这种理念背后的原因是,即便是像MongoDB 这样的可扩展数据库,扩展应用层也要比扩展数据库层容易得多。将事务交由客户端来处理,就减轻了数据库扩展的负担。

在客户端生成ObjectId,驱动程序能够提供更加丰富的API。例如,驱动程序可以有自己的insert 方法,可以返回生成的ObjectId,也可以直接将其插入文档。如果驱动程序允许服务器生成ObjectId,那么将需要单独的查询,以确定插入的文档中的"_id" 值。

设计思路

创建一个序列计数的文档,记录所有文档的名称和序列值,序列值设置默认0,每次进行插入操作的时候,序列值+1,作为本次操作的id。

程序实现

开发环境:IntelliJ IDEA+JAVA8+SpringBoot

1 创建序列计数类,用于存储各文档以及文档序列值。

2 自定义注解

3 定义实体类,自己要实现自增的实体类(get、set),与文档一一对应

4 定义监听类SaveEventListener。重写save方法。在每次存储时候进行主键自增

5.然后测试(中间的111113删除掉了)

           

注意

如果根据主键查询的话要进行转化:

到此,MongoDB的主键自增就完成了。

总结
经过测试,以上流程没有问题,会得到期望的结果,但是有以下几点需要注意:

(1)为什么我在Student类中为主键赋了一个默认值0L?

答:我在此自增方式原作者文章中发现这么一句,“注意自增ID的类型不要定义成Long这种包装类,mongotemplate的源码里面对主键ID的类型有限制”。测试后发现,如果ID定义为原生类型确实是没有问题的。当ID定义为包装类的情况下,如果在onBeforeConvert方法之前没有给ID设置值,是会报错的,我猜测可能是因为内部转换类型时如果ID是空值而无法转换引起的,因此,我赋了一个默认值,这样就不会报错了,包装类也可以使用(不过这样好像跟原生类型就没什么区别了,没什么意义)。

(2)这个监听器会不会影响修改操作?

答:测试发现,不会影响,水平有限,本人也不知作何解释,不要打我……

(3)这种方式会有并发问题吗?

答:不会的!根据官方文档说明,findAndModify一个原子性操作,不过有这么一句“When the findAndModify command includes the upsert: true option and the query field(s) is not uniquely indexed, the command could insert a document multiple times in certain circumstances.”,大概意思是说当查询和更新两个操作都存在时,如果查询的字段没有唯一索引的话,该命令可能会在某些情况下更新/插入 文档多次,参考链接:戳我戳我。以上演示的是只存储了集合所对应的实体类的短名称,短名称是会重复的,所以这种方法不妥,还是记录长名称吧

菜鸟程序员,若有需修正之处,望指正~

 

参考文章:[代码与酒]https://blog.csdn.net/qq_16313365/article/details/72781469

【Mongodb】后台主键_id自增(Java版本)的更多相关文章

  1. 支付宝小程序serverless---插入数据后获取数据的主键_id(mongodb)

    支付宝小程序serverless---插入数据后获取数据的主键_id(mongodb) 博客说明 文章所涉及的资料来自互联网整理和个人总结,意在于个人学习和经验汇总,如有什么地方侵权,请联系本人删除, ...

  2. SqlServer 不是主键 如何自增

    SqlServer 不是主键 如何自增:INSERT INTO dbo.表 VALUES('14-19周',0,(select COUNT(1) from dbo.表)+1) (select COUN ...

  3. SQL语句获取数据库中的表主键,自增列,所有列

    SQL语句获取数据库中的表主键,自增列,所有列   获取表主键 1:SELECT TABLE_NAME,COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_U ...

  4. powerdesigner设置主键为自增字段,设置非主键为唯一键并作为表的外键

    转自:https://www.cnblogs.com/CoffeeHome/archive/2014/06/04/3767501.html 这里powerdesigner连接的数据库是以mysql为例 ...

  5. 修改mysql表结构,添加一个主键索引自增字段,修改原来的主字段为普通字段

    原来有一个字段id,为自增,主键,索引.现在要新增一个字段s_id为自增,主键,索引.同时把原来的主字段改成普通字段,默认值为0. Alter table e_diamond_jhds change ...

  6. EF 实体字段设置主键和自增

    [Key] //主键 [DatabaseGenerated(DatabaseGeneratedOption.Identity)] //设置自增 public int id { get; set; } ...

  7. SQL server 获得 表的主键,自增键

    主键: @tableName --表名 @id ---表对应的id SELECT SYSCOLUMNS.name FROM SYSCOLUMNS,SYSOBJECTS,SYSINDEXES,SYSIN ...

  8. sqlserver修改主键为自增

    使用PowerDesigner创建一张表, 拷贝建表语句发现ID不是自增的, 以下是修改语句: ALTER TABLE USER_JOB_EXE_REC DROP COLUMN id; , ); 注: ...

  9. sql server sql查询数据库的表,字段,主键,自增,字段类型等信息

    1.查询数据表的属性(名称.说明.是否主键.数据类型.是否自增) SELECT t1.name columnName,case when t4.id is null then 'false' else ...

随机推荐

  1. mysql建表和建数据库语句

    一.数据库操作语言 数据库在操作时,需要使用专门的数据库操作规则和语法,这个语法就是 SQL(Structured Query Language) 结构化查询语言. SQL 的主要功能是和数据库建立连 ...

  2. 网络拓扑实例10:MSTP+VRRP组合组网

    组网图形 MSTP+VRRP组合简介 网络中部署VRRP负载分担时,多台设备同时承担业务,每个虚拟设备都包括一个Master设备和若干个Backup设备.如果为了接入备份需要同时部署冗余链路,则需要部 ...

  3. ubantu+nginx+uwsgi+django部署

    1.更新ubantu的apt apt-get update 必要时候更新系统:      apt-get upgrade 2.远程连接服务器 ssh 用户名@ip 上传代码 :        scp ...

  4. python核心高级学习总结7---------正则表达式

    正则表达式在爬虫项目中应用很广泛,主要方面就是在字符串处理方面,经常会涉及到字符串格式的校验,用起来经常要查看文档才能完成,所以抽了个时间将正则的内容复习了一下. Start re---导入re模块使 ...

  5. win10系统rational rose 安装后打开弹框显示java.lang.ClassNotFoundException 解决方案

    场景复现:安装Rational Rose,按照破解方法完成后,打开程序,会弹出对话框显示java.lang.ClassNotFoundException,在关闭程序时也会弹出一个对话框,并且程序不能关 ...

  6. 【科技】位运算(bitset)优化最长公共子序列算法

    最长公共子序列(LCS)问题 你有两个字符串 \(A,B\),字符集为 \(\Sigma\),求 \(A, B\) 的最长公共子序列. 简单动态规划 首先有一个广为人知的 dp:\(f_{i,j}\) ...

  7. 【题解】「UVA681」Convex Hull Finding

    更改了一下程序的错误. Translation 找出凸包,然后逆时针输出每个点,测试数据中没有相邻的边是共线的.多测. Solution 首先推销一下作者的笔记 由此进入>>> ( ...

  8. 【Django Python版本对应】

    使用Python36 时应该使用Django版本1.11.4 pip install django==1.11.4 版本对应表: Django version Python versions 1.8 ...

  9. Day1 字符串格式化

    1.占位符方式:占位符: %d 整数 %012d 数字位数至少长度为12位,不足的前面加0填充. >>> 'Hello,%s,%012d' % ('a',12345678901234 ...

  10. Redis数据持久化(RDB、AOF)

    1. 简介   Redis作为内存型数据库,数据都保存在内存中,如果重启或意外宕机后,数据会全部丢失.因此,Redis提供了完善的持久化机制,将内存中的数据持久化到磁盘上,避免了完整性和安全性的问题, ...