java中实现MongoDB主键自增

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 {

    @Autowired
    MongoTemplate mongo;

    @Override
    public void onBeforeConvert(BeforeConvertEvent 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.参考

  • https://www.jianshu.com/p/3418e32ce757
  • https://www.jianshu.com/p/fba68ec120b2

你可能感兴趣的:(mongodb,springboot,springboot)