java中实现MongoDB主键自增
1.定义序列实体类SeqInfo: 存储每个集合的ID记录
//@Document 把一个java类声明为mongodb的文档,可以通过collection参数指定这个类对应的文档
@Document(collection = "sequence")
public class SeqInfo {
@Id
private String id;//主键
private Long seqId;//序列值
private String collName;//集合名称
...
...
2.自定义注解:AutoIncKey
//标识注解:标识主键ID需要自动增长
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoIncKey {
}
3.定义自动增长ID的监听器: 在保存对象时,通过反射方式为其生成ID
//@Component泛指组件,把SaveEventListener 加入容器
@Component
public class SaveEventListener extends AbstractMongoEventListener<Object> {
@Autowired
MongoTemplate mongo;
@Override
public void onBeforeConvert(BeforeConvertEvent<Object> event) {
final Object source = event.getSource();
if (source != null) {
ReflectionUtils.doWithFields(source.getClass(),new ReflectionUtils.FieldCallback(){
@Override
public void doWith(Field field)throwsIllegalArgumentException,
IllegalAccessException {
//将一个字段设置为可读写,主要针对private字段;
ReflectionUtils.makeAccessible(field);
// 如果字段添加了我们自定义的AutoValue注解
if (field.isAnnotationPresent(AutoIncKey.class)
&& field.get(source) instanceof Number
&& field.getLong(source) == 0) {
// 设置自增ID
field.set(source, getNextAutoId(source.getClass().getSimpleName()));
}
}
});
}
}
/*1.8 以前实现方法如下
@Override
public void onBeforeConvert(final Object source) {
if (source != ) {
ReflectionUtils.doWithFields(source.getClass(), new ReflectionUtils.FieldCallback() {
public void doWith(Field field) throws
IllegalArgumentException, IllegalAccessException {
ReflectionUtils.makeAccessible(field);
// 如果字段添加了我们自定义的AutoIncKey注解
if (field.isAnnotationPresent(AutoIncKey.class)) {
// 设置自增ID
field.set(source, getNextAutoId(source.getClass().getSimpleName()));
}
}
});
}
}*/
// 获取下一个自增ID
private Long getNextAutoId(String collName) {
Query query = new Query(Criteria.where("collName").is(collName));
Update update = new Update();
update.inc("seqId", 1);
FindAndModifyOptions options = new FindAndModifyOptions();
options.upsert(true);
options.returnNew(true);
SeqInfo seq = mongo
.findAndModify(query, update, options, SeqInfo.class);
return seq.getSeqId();
}
}
4.定义测试的实体类以及数据访问类
@Document(collection = "user")
public class User {
@AutoIncKey
@Id
public long id;
@Field
public String name;
@Field
public int age;
public User(String name,int age){
this.name = name;
this.age = age;
}
...
public interface UserRepository extends MongoRepository<User, String> {
}
5.测试
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBootMongodbApplicationTests {
@Autowired
UserRepository userRepository;
@Test
public void test(){
userRepository.deleteAll();
User user1 = new User("Helen", 18);
User user2 = new User("Steven", 18);
userRepository.save(user1);
userRepository.save(user2);
System.out.println("Helen的id: "+user1.getId());
System.out.println("Steven的id: "+user2.getId());
}
}
6.参考