1. 概述
在本教程中,我们将学习如何在 Spring Boot 项目中为 MongoDB 实现一个顺序自增字段。
⚠️ 使用 MongoDB 作为数据库时,无法像 JPA + SQL 那样直接使用 @GeneratedValue
注解。 因此我们需要一种替代方案来实现类似的效果。
✅ 解决方案其实很简单:我们创建一个专门用于存储序列号的集合(collection),每次插入新记录前从中获取下一个自增值即可。
2. 依赖配置
首先,在 pom.xml
中添加以下 Spring Boot Starter:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
</dependencies>
版本管理由 spring-boot-starter-parent
自动处理。
3. 数据结构设计
如前所述,我们要创建一个专门保存序列号的集合,命名为 database_sequences
。可以用 mongo
shell 或者 MongoDB Compass 手动创建。
对应的 Java 模型类如下:
@Document(collection = "database_sequences")
public class DatabaseSequence {
@Id
private String id;
private long seq;
// 省略 getter 和 setter
}
然后我们再创建一个用户集合 users
及其对应的模型类:
@Document(collection = "users")
public class User {
@Transient
public static final String SEQUENCE_NAME = "users_sequence";
@Id
private BigInteger id;
private String email;
// 省略 getter 和 setter
}
📌 注意点:
SEQUENCE_NAME
是该集合唯一标识的序列名。- MongoDB 要求主键字段类型必须是
String
、ObjectId
或BigInteger
,才能自动生成_id
。 - 使用
@Transient
注解防止SEQUENCE_NAME
被持久化到数据库。
4. 实现自增逻辑
现在我们来实现一个服务类,用于生成自增 ID:
public long generateSequence(String seqName) {
DatabaseSequence counter = mongoOperations.findAndModify(
query(where("_id").is(seqName)),
new Update().inc("seq", 1),
options().returnNew(true).upsert(true),
DatabaseSequence.class
);
return !Objects.isNull(counter) ? counter.getSeq() : 1;
}
使用方式也很简单粗暴:
User user = new User();
user.setId(BigInteger.valueOf(sequenceGenerator.generateSequence(User.SEQUENCE_NAME)));
user.setEmail("[email protected]");
userRepository.save(user);
如果要列出所有用户:
List<User> storedUsers = userRepository.findAll();
storedUsers.forEach(System.out::println);
✅ 进阶优化:自动填充 ID
每次手动设置 ID 太麻烦?可以用 MongoDB 生命周期监听器来简化操作。
创建一个监听器类继承 AbstractMongoEventListener<User>
并重写 onBeforeConvert()
方法:
@Override
public void onBeforeConvert(BeforeConvertEvent<User> event) {
if (event.getSource().getId().intValue() < 1) {
event.getSource().setId(BigInteger.valueOf(
sequenceGenerator.generateSequence(User.SEQUENCE_NAME)
));
}
}
这样,每次保存新的 User
对象时,ID 就会自动填充了,非常优雅!
5. 总结
在这篇文章中我们实现了 MongoDB 中模拟 SQL 自增主键的功能:
✅ 通过一个独立的序列集合保存当前最大值
✅ 利用 findAndModify
原子操作保证并发安全
✅ 结合 Spring Data MongoDB 生命周期事件实现自动填充
💡 Hibernate 在处理自增主键时也采用了类似的机制。
完整代码示例可以在 GitHub 上找到:Spring Boot with MongoDB Auto-Increment