转载自:https://blog.youkuaiyun.com/qq_38258310/article/details/88616821
第一步:自定义一个自增长标识,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<Object>
{
@Autowired
private MongoTemplate mongoTemplate;
/**
* onBefore代表前置处理
* @param event
*/
@Override
public void onBeforeConvert(BeforeConvertEvent<Object> 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的意思。 | |
---|---|