MongoDB实现主键自增

由于MySQL的使用习惯,导致在使用MongoDB的过程中没有自增长的ID十分不爽,而自动生成的序列则又没有什么可读性,恰巧在看书的过程中发现有讲到,所以记录下。

 

第一步:自定义一个自增长标识,Java的注解就是一个非常优秀的选择,代码如下:

package com.lsm1998.userservice.mongo;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @作者:刘时明
 * @时间:2019/3/17-11:33
 * @说明:自增长标识
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface GeneratedValue
{

}

 

第二步:创建一个MongoDB文档实体,用来记录每个集合中最近的ID,代码如下:

package com.lsm1998.userservice.mongo;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;

/**
 * @作者:刘时明
 * @时间:2019/3/17-11:43
 * @说明:保存每个集合最近一次的ID
 */
@Document(collection = "sequence")
public class SequenceID
{
    @Id
    private String id;
    @Field("seq_id")
    private long seqId;
    @Field("coll_name")
    private String collName;

    public String getId()
    {
        return id;
    }

    public void setId(String id)
    {
        this.id = id;
    }

    public long getSeqId()
    {
        return seqId;
    }

    public void setSeqId(long seqId)
    {
        this.seqId = seqId;
    }

    public String getCollName()
    {
        return collName;
    }

    public void setCollName(String collName)
    {
        this.collName = collName;
    }
}

 

第三步:实现一个自定义的MongoDB保存监听器,代码如下:

package com.lsm1998.userservice.mongo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.FindAndModifyOptions;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.mapping.event.AbstractMongoEventListener;
import org.springframework.data.mongodb.core.mapping.event.BeforeConvertEvent;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;

/**
 * @作者:刘时明
 * @时间:2019/3/17-11:35
 * @说明:保存监听器
 */
@Component
public class SaveMongoEventListener extends AbstractMongoEventListener
{
    @Autowired
    private MongoTemplate mongoTemplate;

    /**
     * onBefore代表前置处理
     * @param event
     */
    @Override
    public void onBeforeConvert(BeforeConvertEvent event)
    {
        Object source = event.getSource();
        if (source != null)
        {
            // 当写一个字段的时候触发回调
            ReflectionUtils.doWithFields(source.getClass(),(field)->
            {
                // 使用反射设置字段可以改变
                ReflectionUtils.makeAccessible(field);
                // 判断是否有自增标识
                if(field.isAnnotationPresent(GeneratedValue.class))
                {
                    field.set(source,getNextId(source.getClass().getSimpleName()));
                }
            });
        }
    }

    /**
     * 给定集合名,将之中的seqId自增一次,并返回
     * @param collName
     * @return
     */
    private long getNextId(String collName)
    {
        Query query = new Query(Criteria.where("collName").is(collName));
        Update update = new Update();
        update.inc("seqId", 1);
        // findAndModify是原子操作,避免并发问题
        FindAndModifyOptions options = new FindAndModifyOptions();
        options.upsert(true);
        options.returnNew(true);
        SequenceID seqId = mongoTemplate.findAndModify(query, update, options, SequenceID.class);
        return seqId.getSeqId();
    }
}
 
  

最后自行测试就可以了,只要在文档实体类的ID字段加上@GeneratedValue注解即可,当然,ID字段的属性也需要是Long类型,如果你想指定其他数值,例如int,则需要稍加修改。

总结:实现MongDB主键自增的关键在于AbstractMongoEventListener,这是Spring提供的关于整合MongoDB的处理监听器,它提供了一些前置、后置的处理方法,类似于MySQL中的触发器,都有AOP的意思。

你可能感兴趣的:(SpringBoot)