用了mongodb之后要是问我mongo和mysql的区别在哪里?第一点我就会想到的是没有自增ID,mongo里面是ObjectId。今天我们就自己来实现自增的ID。
像mysql这种数据库是内部实现了自增ID,今天我们要自己实现一个,不知道大家有没有具体的思路。
当然mongodb官网上也提供了一种实现的方法,就是自定义一个获取自增ID的方法,然后每次插入的时候就去获取下一个ID,再插入到集合中。
我们既然用了spring-data-mongodb这个框架,就要基于这个框架来实现一套逻辑,而且每次插入都要自己去手动的调用方法获取一次ID,是不是太繁琐了。
我们用的是监听的模式,在数据插入到集合之前,我们通过反射将ID设置到保存的对象中,来实现自动设置,对写代码的人来说完全透明。
首先我们定义一个用于存储每个集合的ID记录,记录每个集合的自增ID到了多少。
@Document(collection = "sequence") public class SequenceId { @Id private String id; @Field("seq_id") private long seqId; @Field("coll_name") private String collName; }
接下来定义我们测试的实体类,注意自增ID的类型不要定义成Long这种包装类,mongotemplate的源码里面对主键ID的类型有限制。
@Documentpublic class Student {
@GeneratedValue
@Id
private long id;
private String name;
}
下面我们定义个注解来标识此字段要自动增长ID,有些场景下可能不需要自动增长,需要自动增长的时候我们加上这个注解。
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD })
public @interface GeneratedValue {
}
接下来就是实现自动注入ID的监听器了,需要配置让spring管理
<bean class="com.cxytiandi.mongo.autoid.SaveMongoEventListener"></bean>
public class SaveMongoEventListener extends AbstractMongoEventListener<Object> { @Resource private MongoTemplate mongoTemplate; @Override public void onBeforeConvert(final Object source) { if(source != null) { ReflectionUtils.doWithFields(source.getClass(), new ReflectionUtils.FieldCallback() { public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException { ReflectionUtils.makeAccessible(field); if (field.isAnnotationPresent(GeneratedValue.class)) { //设置自增ID field.set(source, getNextId(source.getClass().getSimpleName())); } } }); } } /** * 获取下一个自增ID * @author yinjihuan * @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); FindAndModifyOptions options = new FindAndModifyOptions(); options.upsert(true); options.returnNew(true); SequenceId seqId = mongoTemplate.findAndModify(query, update, options, SequenceId.class); return seqId.getSeqId(); } }
findAndModify()是原子操作,所以不用担心并发问题
源码下载:http://cxytiandi.com/code/detail/1