mongodb没有关于自增id的实现
1。一般思路是取出最大的id ,然后+1。 除非取最大的id和+1这两个步骤是原子的,否则一定存在并发问题(有可能两个线程同时取到一个id),显然这样不可取。
2。另外,也可以将插入和具体程序解耦, 将所有的插入操作提交到一个可阻塞的队列,然后多个线程不断的消费这个队列。 由这个队列控制生成id,这样不会存在同步问题。 但是当有大量的插入操作时,消费线程变多,会在对头有很大竞争。
3 。也可以在程序启动的时候初始化一个collection的最大 id, 然后原子的去更新这个id
public class UserCollection {
private static final String collectionName = "user";
private final AtomicInteger maxId = new AtomicInteger();
// single instance
private static UserCollection collection = new UserCollection();
private UserCollection() {
int max = MongoUtil.getMaxId(collectionName);
maxId.set(max);
}
public static UserCollection getInstance(){
return collection;
}
public int getIncreasedId() {
return maxId.getAndIncreased()
}
}
对于多个collection的情况,可以用map去保存collectionName 和maxId 之间的对于关系(可以lazy init)。 然后提供统一的接口
public class MongoIdUtil {
private final ConcurrentHashMap<String, Integer> nameAndId = new ConcurrentHashMap<String, Integer>();
public int getIncreasedId(String name) {
for(;;) {
Integer id = nameAndId.get(name);
if(id == null) {
DBCollection collection = MongoUtil.getCollection(name);
if(collection == null)
throw new RuntimeException("mongo collection with name: " + name + "not exist!");
@SuppressWarnings("unchecked")
List<Integer> distinct = collection.distinct("id");
int maxId = Collections.max(distinct) + 1;
if(nameAndId.putIfAbsent(name, maxId) != null) continue;//loop when failure
return maxId;
}
int newId = id + 1;
if(nameAndId.replace(name, id, newId)) {
return newId;
}
}
}
private MongoIdUtil() {};
private static MongoIdUtil instanse = new MongoIdUtil();
public static MongoIdUtil getInstance() {
return instanse;
}
}