mongo实现自增id

2018/04/05 22:42
阅读数 18


摘要

Mongo 的free schema,提供了灵活的数据结构,和快速开发的能力,但是也造成了松散的数据组织形式。比如说有些字段不允许为null的,需要符合一定格式的。也就是数据库的校验,validator。这个功能在mongo 3.2才提供,之前是并没有的。这里提供一种基于MongoEvent的解决方案,来实现对于数据的校验。

mongo event

  1. Mongo 提供了Event的类型MongoMappingEvent 类,然后其他的具体事件类型都继承这个类,比兔BeforeConvertEvent,BeforeConvertEvent,BeforeSaveEvent.

  2. AbstractMongoEventListener 抽象类事件方法, onBeforeConvertEvent(),onBeforeConvertEvent()方法,在ApplicationEvent类中提供了基于方法参数MongoMappingEvent去调用不同的事件方法

提供了Mongo Event的类型,以及处理方法

  
    
  
  
  1. public void onApplicationEvent(MongoMappingEvent<?> event) {

  2.            // 根据事件类型,来执行不同的方法

  3.    if (event instanceof AfterLoadEvent) {

  4.        AfterLoadEvent<?> afterLoadEvent = (AfterLoadEvent<?>) event;

  5.        if (domainClass.isAssignableFrom(afterLoadEvent.getType())) {

  6.            onAfterLoad((AfterLoadEvent<E>) event);

  7.        }

  8.        return;

  9.    }

  10.    if (event instanceof AbstractDeleteEvent) {

  11.        Class<?> eventDomainType = ((AbstractDeleteEvent) event).getType();

  12.        if (eventDomainType != null && domainClass.isAssignableFrom(eventDomainType)) {

  13.            if (event instanceof BeforeDeleteEvent) {

  14.                onBeforeDelete((BeforeDeleteEvent<E>) event);

  15.            }

  16.            if (event instanceof AfterDeleteEvent) {

  17.                onAfterDelete((AfterDeleteEvent<E>) event);

  18.            }

  19.        }

  20.        return;

  21.    }

  22.    Object source = event.getSource();

  23.    // Check for matching domain type and invoke callbacks

  24.    if (source != null && !domainClass.isAssignableFrom(source.getClass())) {

  25.        return;

  26.    }

  27.    if (event instanceof BeforeConvertEvent) {

  28.        onBeforeConvert((BeforeConvertEvent<E>) event);

  29.    } else if (event instanceof BeforeSaveEvent) {

  30.        onBeforeSave((BeforeSaveEvent<E>) event);

  31.    } else if (event instanceof AfterSaveEvent) {

  32.        onAfterSave((AfterSaveEvent<E>) event);

  33.    } else if (event instanceof AfterConvertEvent) {

  34.        onAfterConvert((AfterConvertEvent<E>) event);

  35.    }

  36. }


  1. 事件的publish 发生在mongoTemplate类中 之前有介绍过,spring-data-mongo中所有的数据库操作都在mongoTemplate中,典型的insert操作

  
    
  
  
  1. protected <T> void doInsert(String collectionName, T objectToSave, MongoWriter<T> writer) {

  2.        initializeVersionProperty(objectToSave);

  3.        // 调用onBeforeConvert

  4.        maybeEmitEvent(new BeforeConvertEvent<T>(objectToSave, collectionName));

  5.        assertUpdateableIdIfNotSet(objectToSave);

  6.        DBObject dbDoc = toDbObject(objectToSave, writer);

  7.        // 调用onBeforeSaveEvent

  8.        maybeEmitEvent(new BeforeSaveEvent<T>(objectToSave, dbDoc, collectionName));

  9.        Object id = insertDBObject(collectionName, dbDoc, objectToSave.getClass());

  10.        populateIdIfNecessary(objectToSave, id);

  11.        // 调用onAfterSaveEvent

  12.        maybeEmitEvent(new AfterSaveEvent<T>(objectToSave, dbDoc, collectionName));

  13.    }

实现mongo自增id

提供一个@MongoAutoId的注解,然后onBeforeConvert事件中进行转换。

  
    
  
  
  1. package com.fs.mongo.dao;

  2. import com.fs.mongo.annotation.MongoAutoId;

  3. import com.fs.mongo.model.MongoId;

  4. import org.slf4j.Logger;

  5. import org.slf4j.LoggerFactory;

  6. import org.springframework.beans.factory.annotation.Autowired;

  7. import org.springframework.data.mongodb.core.FindAndModifyOptions;

  8. import org.springframework.data.mongodb.core.MongoTemplate;

  9. import org.springframework.data.mongodb.core.mapping.event.AbstractMongoEventListener;

  10. import org.springframework.data.mongodb.core.mapping.event.BeforeConvertEvent;

  11. import org.springframework.data.mongodb.core.mapping.event.BeforeSaveEvent;

  12. import org.springframework.data.mongodb.core.query.Criteria;

  13. import org.springframework.data.mongodb.core.query.Query;

  14. import org.springframework.data.mongodb.core.query.Update;

  15. import org.springframework.stereotype.Repository;

  16. import org.springframework.util.ReflectionUtils;

  17. /**

  18. * @author cnstonefang@gmail.com

  19. */

  20. @Repository

  21. public class MongoListener extends AbstractMongoEventListener<Object> {

  22.    private static final Logger LOG = LoggerFactory.getLogger(MongoListener.class);

  23.    @Autowired

  24.    private MongoTemplate mongoTemplate;

  25.    @Override

  26.    public void onBeforeConvert(final BeforeConvertEvent<Object> event) {

  27.        final Object source = event.getSource();

  28.        if (source != null) {

  29.            ReflectionUtils.doWithFields(source.getClass(), new ReflectionUtils.FieldCallback() {

  30.                @Override

  31.                public void doWith(final java.lang.reflect.Field field)

  32.                        throws IllegalArgumentException, IllegalAccessException {

  33.                    ReflectionUtils.makeAccessible(field);

  34.                    if (field.isAnnotationPresent(MongoAutoId.class) && field.get(source) == null) {

  35.                        field.set(source, getId(event.getCollectionName()));

  36.                    }

  37.                }

  38.            });

  39.        }

  40.    }

  41.    /**

  42.     * 获取自增id

  43.     * 这边是利用mongo的findAndModify的原子性实现的

  44.     * 也可以使用redis来实现

  45.     */

  46.    private Long getId(final String collName) {

  47.        final Query query = new Query().addCriteria(

  48.                new Criteria(MongoId.FIELD_COLLNAME).is(collName));

  49.        final Update update = new Update();

  50.        update.inc(MongoId.FIELD_SEQID, 1);

  51.        final FindAndModifyOptions options = new FindAndModifyOptions().upsert(true).returnNew

  52.                (true);

  53.        final MongoId sequence = mongoTemplate.findAndModify(query, update, options,

  54.                MongoId.class);

  55.        return sequence.getSeqId();

  56.    }

  57. }

完整代码


本文分享自微信公众号 - 方丈的寺院(gh_c98f244e174d)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部