У меня есть метод, который генерирует буквенно-цифровую последовательность на основе определенного шаблона. Я хочу сохранить сгенерированную последовательность, и когда в следующий раз я захочу создать новую, она должна начинаться с последней сохраненной. У меня проблема с этим, потому что это буквенно-цифровой. Кроме того, я хочу поместить сгенерированные идентификаторы в файл 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();
}
общедоступный 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();
}
Я хочу, чтобы сохранение и проверка того, существует ли оно, выполнялись в этом методе, который я разместил выше. Как лучше всего это сделать?
Должен ли идентификатор быть уникальным во всей базе данных? Или он уникален только в конкретном наборе терминалов, например set1(id - 0000
, 0001
, 0002
и т.д.), set2(id - 0000
, 0001
и т.д.)?
Он должен быть уникальным во всей базе данных.
Вы можете сделать это, добавив новую таблицу в БД. Поскольку он должен быть уникальным для всей базы данных, эта таблица будет содержать одну строку, в которой отслеживается следующее целое число, используемое для генерации идентификатора.
Я предполагаю, что вы используете данные весны, тогда ваша сущность может быть примерно такой:
public class Sequence {
private String id;
private int next;
//getters and setters
}
Репозиторий:
@Repository
public interface SequenceRepository extends MongoRepository<Sequence, String> {
}
Предполагая, что вы используете монго из тега вопроса.
Начальное значение для 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();
}
Здесь есть некоторые предположения, но это общий алгоритм, которому вы должны следовать.
Важный: Это решение не учитывает возможность одновременного доступа к таблице, что может привести к дублированию идентификаторов. Если у вас есть такие варианты использования, вы можете рассмотреть:
generateTerminalIDs
, что заставляет другие потоки, которым нужен доступ для следующего, ждать, пока не будут сгенерированы все идентификаторы.Редактировать: SaveAndFlush эквивалентен для создания или обновления. Весной это реализовано таким образом - если у объекта есть свойство id (в данном случае sequence.id != null
), сделайте обновление, иначе создайте (вставьте). В вашем случае создайте строку при инициализации новой таблицы, обновите ее при создании идентификаторов.
О findAll()
- он возвращает список со всеми строками/сущностями из таблицы. Сюда repository.findAll()
вернется List<Sequence>
. repository.findAll().get(0)
вернет Sequence
, строку первый и единственный в таблице.
Большое спасибо. Наличие некоторых проблем. Я не использую Springboot. Таким образом, у меня нет доступа к saveAndFlush(). Кроме того, отсутствует findAll.get(0). Что вернет findAll.get(0), чтобы я мог лучше понять, как реализовать здесь. В настоящее время думаю об использовании find.first() в MongoJackson.
@Curious Проверьте редактирование.
В настоящее время только 0, и введенное число сохраняется в БД. Я обновлю вопрос, сохранив и найдя все эквиваленты, которые я создал. Кроме того, в какой части кода я должен разместить эту последовательность sequence = new Sequence(); последовательность.setNext (0); this.repository.saveAndFlush (последовательность); внутри функции, где она генерируется, или снаружи
@ Любопытно, я не совсем понимаю первый вопрос. Что такое введенное число? Насчет второго вопроса, куда ставить - ... sequence.setNext(0); ...
, однозначно снаружи, это инициализация вашей последовательности. Процитирую себя - Initialise and save in db at appropriate time, maybe app startup. Just do this initialization only once.
Первый вопрос я имел в виду terminalDto. Проблема в том, что последовательность (то есть идентификатор терминала) не сохраняется, и если я удалю то, что у меня есть в БД, это выдаст ошибку, что последовательность равна нулю
@ Любопытно, я не эксперт по монго, но, насколько мне известно, collection.save()
следует вставлять или обновлять, в зависимости от того, есть ли идентификатор. Боюсь, недостаточно данных для решения этой проблемы, по крайней мере, для меня. Моя единственная идея заключается в том, что если проблема возникает только при обновлении последовательности, вы можете использовать некоторые из методов collection.update...()
, но это выстрел в темноту.
Большое спасибо. Итак, я нашел способ сохранить, единственная сложность сейчас - сохранить список (последовательности). Это все, что осталось
Внес некоторые изменения и получил желаемый результат. Спасибо!
@chaosfire вот продолжение вопроса, который я задал ранее.