如何在 mongodb 中保存字母数字序列并从 MongoDB 中最后保存的序列开始生成
How to save alphanumeric sequence in mongodb and start generating from the last saved sequence in MongoDB
我有一种方法可以根据特定模式生成字母数字序列。我想保存生成的序列,下次我想生成一个新序列时,它应该从上次保存的序列开始。我遇到这种情况的问题,因为它是字母数字的。另外,我想将生成的 ID 放入 excel 文件中。
下面这两种方法检查它是否已经存在,并尝试获取最后保存的项目。
public Optional<Terminal> findByGeneratedTerminalIDs(String id){
return Optional.ofNullable(this.collection.findOne(Filters.eq("generatedTerminalID", id)));
}
public Optional<FindIterable<Terminal>> findLastGeneratedTerminalID(String generatedTerminalID) {
return Optional.ofNullable(this.collection.find(Filters.eq("generatedTerminalID", generatedTerminalID)).
sort(Sorts.descending("generatedTerminalID")).limit(1));
}
这是更新后的存储库
private JacksonMongoCollection<Sequence> collection;
public SequenceRepository(JacksonMongoCollection<Sequence> collection) {
this.collection = collection;
}
public Sequence save(Sequence sequence) {
collection.save(sequence);
return sequence;
}
public Sequence findAllSequences(Sequence sequence) {
return collection.find(Filters.eq("generatedTerminalID", sequence.getGeneratedTerminalID())).first();
}
public BaseResponse generateTerminalIDs(TerminalIDDTO terminalDto) {
Sequence sequence = new Sequence();
sequence.setNext(0);
sequenceRepository.save(sequence);
int totalLength = 8;
int numberOfIds = terminalDto.getNumberOfTerminals();
int countRemainingSymbols = totalLength - START.length();
//there should be only 1 row at all times
sequence = this.sequenceRepository.findAllSequences(sequence);
int start = sequence.getNext();//start generation of sequences from the value of next
int next = start + numberOfIds;//this will be next value of sequence.next
for (int i = start; i < next; i++) {
StringBuilder end = new StringBuilder();
int current = i;
int remainder = current % ALPHANUMERIC.length();//the index of next character
do {
end.append(ALPHANUMERIC.charAt(remainder));
current /= ALPHANUMERIC.length();//update to check if we need to add more characters
remainder = current % ALPHANUMERIC.length();//update index, only used if more chars are needed
} while (current > 0);
int padCount = countRemainingSymbols - end.length();
StringBuilder result = new StringBuilder(START).append("-");//- is for easier debugging, remove it for your case
for (int j = 0; j < padCount; j++) {
result.append("0");
}
result.append(end.reverse());
log.info("These are the values {}", result);
}
//update next value and save in db
sequence.setNext(next);
sequenceRepository.save(sequence);
return BaseResponse.builder().status(true).message("TerminalIDs have been generated").build();
}
我想保存并检查它是否存在,用我上面发布的这个方法来完成。最好的方法是什么?
您可以将新的 table 添加到数据库中。由于它对于整个数据库必须是唯一的,因此 table 将保留一行,跟踪下一个用于生成 ID 的整数。
我假设你使用 spring 数据,那么你的实体可能是这样的:
public class Sequence {
private String id;
private int next;
//getters and setters
}
存储库:
@Repository
public interface SequenceRepository extends MongoRepository<Sequence, String> {
}
假设您使用的是问题标签中的 mongo。
next 的初始值应为零。
Sequence sequence = new Sequence();
sequence.setNext(0);
this.repository.saveAndFlush(sequence);
在适当的时候初始化并保存在数据库中,也许是应用程序启动。只做一次这个初始化。
那么生成方法可能是这样的:
@Autowired
private SequenceRepository repository;
public BaseResponse generateTerminalIDs(TerminalIDDTO terminalDto) {
Terminal terminal = new Terminal();
int totalLength = 8;
int numberOfIds = terminalDto.getNumberOfTerminals();
int countRemainingSymbols = totalLength - START.length();
//there should be only 1 row at all times
Sequence sequence = this.repository.findAll().get(0);
int start = sequence.getNext();//start generation of sequences from the value of next
int next = start + numberOfIds;//this will be next value of sequence.next
for (int i = start; i < next; i++) {
StringBuilder end = new StringBuilder();
int current = i;
int remainder = current % ALPHANUMERIC.length();//the index of next character
do {
end.append(ALPHANUMERIC.charAt(remainder));
current /= ALPHANUMERIC.length();//update to check if we need to add more characters
remainder = current % ALPHANUMERIC.length();//update index, only used if more chars are needed
} while (current > 0);
int padCount = countRemainingSymbols - end.length();
StringBuilder result = new StringBuilder(START).append("-");//- is for easier debugging, remove it for your case
for (int j = 0; j < padCount; j++) {
result.append("0");
}
//this should be outside pad loop
result.append(end.reverse());
}
//update next value and save in db
sequence.setNext(next);
this.repository.saveAndFlush(sequence);
return BaseResponse.builder().status(true).message("TerminalIDs have been generated").build();
}
这里有一些假设,但这是您应该遵循的总体算法。
重要提示: 此解决方案未考虑可能同时访问 table,这可能会导致重复 ID。如果您有这样的用例,您可能需要考虑:
- 在
generateTerminalIDs
执行期间锁定 table,从而迫使其他想要访问 next 的线程等待,直到生成所有 ID。
- 获取下一个,并在生成 ID 之前立即更新它。在获取和更新期间锁定 table 可能仍然是一个好主意,但其他想要访问的线程将等待更少。
编辑: SaveAndFlush 等同于创建或更新。在 spring 中,它以这种方式实现 - 如果实体具有 id 属性(在这种情况下为 sequence.id != null
),则进行更新,否则进行创建(插入)。对于您的情况,在初始化新 table 时创建行,在创建 ID 时更新它。
关于 findAll()
- 它 return 是一个包含来自 table 的所有 rows/entites 的列表。这里repository.findAll()
将returnList<Sequence>
。 repository.findAll().get(0)
将 return Sequence
,第一个也是唯一的 行在 table.
我有一种方法可以根据特定模式生成字母数字序列。我想保存生成的序列,下次我想生成一个新序列时,它应该从上次保存的序列开始。我遇到这种情况的问题,因为它是字母数字的。另外,我想将生成的 ID 放入 excel 文件中。
下面这两种方法检查它是否已经存在,并尝试获取最后保存的项目。
public Optional<Terminal> findByGeneratedTerminalIDs(String id){
return Optional.ofNullable(this.collection.findOne(Filters.eq("generatedTerminalID", id)));
}
public Optional<FindIterable<Terminal>> findLastGeneratedTerminalID(String generatedTerminalID) {
return Optional.ofNullable(this.collection.find(Filters.eq("generatedTerminalID", generatedTerminalID)).
sort(Sorts.descending("generatedTerminalID")).limit(1));
}
这是更新后的存储库
private JacksonMongoCollection<Sequence> collection;
public SequenceRepository(JacksonMongoCollection<Sequence> collection) {
this.collection = collection;
}
public Sequence save(Sequence sequence) {
collection.save(sequence);
return sequence;
}
public Sequence findAllSequences(Sequence sequence) {
return collection.find(Filters.eq("generatedTerminalID", sequence.getGeneratedTerminalID())).first();
}
public BaseResponse generateTerminalIDs(TerminalIDDTO terminalDto) {
Sequence sequence = new Sequence();
sequence.setNext(0);
sequenceRepository.save(sequence);
int totalLength = 8;
int numberOfIds = terminalDto.getNumberOfTerminals();
int countRemainingSymbols = totalLength - START.length();
//there should be only 1 row at all times
sequence = this.sequenceRepository.findAllSequences(sequence);
int start = sequence.getNext();//start generation of sequences from the value of next
int next = start + numberOfIds;//this will be next value of sequence.next
for (int i = start; i < next; i++) {
StringBuilder end = new StringBuilder();
int current = i;
int remainder = current % ALPHANUMERIC.length();//the index of next character
do {
end.append(ALPHANUMERIC.charAt(remainder));
current /= ALPHANUMERIC.length();//update to check if we need to add more characters
remainder = current % ALPHANUMERIC.length();//update index, only used if more chars are needed
} while (current > 0);
int padCount = countRemainingSymbols - end.length();
StringBuilder result = new StringBuilder(START).append("-");//- is for easier debugging, remove it for your case
for (int j = 0; j < padCount; j++) {
result.append("0");
}
result.append(end.reverse());
log.info("These are the values {}", result);
}
//update next value and save in db
sequence.setNext(next);
sequenceRepository.save(sequence);
return BaseResponse.builder().status(true).message("TerminalIDs have been generated").build();
}
我想保存并检查它是否存在,用我上面发布的这个方法来完成。最好的方法是什么?
您可以将新的 table 添加到数据库中。由于它对于整个数据库必须是唯一的,因此 table 将保留一行,跟踪下一个用于生成 ID 的整数。
我假设你使用 spring 数据,那么你的实体可能是这样的:
public class Sequence {
private String id;
private int next;
//getters and setters
}
存储库:
@Repository
public interface SequenceRepository extends MongoRepository<Sequence, String> {
}
假设您使用的是问题标签中的 mongo。
next 的初始值应为零。
Sequence sequence = new Sequence();
sequence.setNext(0);
this.repository.saveAndFlush(sequence);
在适当的时候初始化并保存在数据库中,也许是应用程序启动。只做一次这个初始化。
那么生成方法可能是这样的:
@Autowired
private SequenceRepository repository;
public BaseResponse generateTerminalIDs(TerminalIDDTO terminalDto) {
Terminal terminal = new Terminal();
int totalLength = 8;
int numberOfIds = terminalDto.getNumberOfTerminals();
int countRemainingSymbols = totalLength - START.length();
//there should be only 1 row at all times
Sequence sequence = this.repository.findAll().get(0);
int start = sequence.getNext();//start generation of sequences from the value of next
int next = start + numberOfIds;//this will be next value of sequence.next
for (int i = start; i < next; i++) {
StringBuilder end = new StringBuilder();
int current = i;
int remainder = current % ALPHANUMERIC.length();//the index of next character
do {
end.append(ALPHANUMERIC.charAt(remainder));
current /= ALPHANUMERIC.length();//update to check if we need to add more characters
remainder = current % ALPHANUMERIC.length();//update index, only used if more chars are needed
} while (current > 0);
int padCount = countRemainingSymbols - end.length();
StringBuilder result = new StringBuilder(START).append("-");//- is for easier debugging, remove it for your case
for (int j = 0; j < padCount; j++) {
result.append("0");
}
//this should be outside pad loop
result.append(end.reverse());
}
//update next value and save in db
sequence.setNext(next);
this.repository.saveAndFlush(sequence);
return BaseResponse.builder().status(true).message("TerminalIDs have been generated").build();
}
这里有一些假设,但这是您应该遵循的总体算法。
重要提示: 此解决方案未考虑可能同时访问 table,这可能会导致重复 ID。如果您有这样的用例,您可能需要考虑:
- 在
generateTerminalIDs
执行期间锁定 table,从而迫使其他想要访问 next 的线程等待,直到生成所有 ID。 - 获取下一个,并在生成 ID 之前立即更新它。在获取和更新期间锁定 table 可能仍然是一个好主意,但其他想要访问的线程将等待更少。
编辑: SaveAndFlush 等同于创建或更新。在 spring 中,它以这种方式实现 - 如果实体具有 id 属性(在这种情况下为 sequence.id != null
),则进行更新,否则进行创建(插入)。对于您的情况,在初始化新 table 时创建行,在创建 ID 时更新它。
关于 findAll()
- 它 return 是一个包含来自 table 的所有 rows/entites 的列表。这里repository.findAll()
将returnList<Sequence>
。 repository.findAll().get(0)
将 return Sequence
,第一个也是唯一的 行在 table.