在使用MongoDB的时候 (基于spring-mongo) ,我想在插入对象时获取有序自增的主键 ,但是MongoDB的默认规则是生成一串无序 (大致有序) 的字串 .而Spring Data提供的主键生成方法也是随机的 String/BigInteger.
因为分布式情况下 ,有序ID会变得困难 ( ID中心/分布式锁 )
同步问题
获取有序ID的通常做法是 :
创建sequence : key-start-end-step-current 标识/起值/止值/步长/当前值
获取sequence ,current作为主键值
保存current = current + step到数据库作为下一个主键值
但是在多线程情况下 , 2-3可能被多个线程同时运行 ,导致sequence还未保存成功就被下一个获取.
模拟数据库Sequence模型
@AllArgsConstructor
public class Sequence {
@Setter
long current;
public long getCurrent() {
transTime();
return current;
}
public void setCurrent(long current) {
transTime();
this.current = current;
}
private void transTime() {
try {
Thread.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class SequenceServiceTest {
Sequence A;//A型sequence
Sequence B;//B型sequence
/**
* 初始化数据
*/
@Before
public void before() {
A = new Sequence(1L);
B = new Sequence(1L);
}
/**
* 模拟数据库取值
*/
private Sequence getSequence(String name) {
switch (name) {
case "A":
return A;
case "B":
return B;
default:
return null;
}
}
private void waitService(ExecutorService executorService) {
executorService.shutdown();
try {
while (!executorService.awaitTermination(1000, TimeUnit.SECONDS)) {
}
System.out.println("final A:" + A.getCurrent());
System.out.println("final B:" + B.getCurrent());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
非同步代码读写sequence
@Test
public void noSynchronizedTest() {
//10个用户同时需要获取id
ExecutorService executorService = Executors.newFixedThreadPool(10);
//一部分需要A ,一部分需要B
for (int i = 0; i < 1000; i++) {
e