Проблема увеличения счетчика базы данных вручную

Я разрабатываю REST API с использованием Java и Spring Boot для управления покупками и клиентами. В моей базе данных MySQL у меня есть таблица Purchase с колонкой, которая хранит уникальный ticketId, Это не первичный ключ.

Когда новая покупка добавляется (делая PUT запрос), я создаю новую покупку из данных, указанных в запросе, получить максимум ticketId, увеличить его на единицу и сохранить в базе данных. Первичный ключ автоматически увеличивается.

Это мой код:

@Transactional
public boolean saveNewPurchase(PurchaseDTO data) {
  Purchase p = createPurchaseFromData(data);
  Long idTicket = purchaseDao.getMaxIdTicket();
  p.setIdTicket(idTicket + 1);
  save(p);
}

Есть ли здесь проблемы с параллелизмом? Скажем два PUT запросы выполняют этот метод параллельно, они могут получить тот же максимум idTicket так что нарушать уникальный idTicket Ограничение, когда сохранить вторую покупку?

Если так, как я мог решить это? Будет делать метод synchronized решать проблему?

Благодарю.

2 ответа

Решение

Да, здесь есть проблема параллелизма. Два разных потока могут получить одинаковые maxIdTicket, а затем сохранить покупку с тем же ticketId,

Я вижу 3 решения здесь:

  • Используйте синхронизированный
  • Используйте AtomicInteger сохранить счетчик в памяти
  • Используйте конкретную таблицу в MySQL, только с одним столбцом, AUTO_INCREMENT и вставлять / получать строки каждый раз, когда вам нужно значение счетчика. С другими RDBMS вы можете использовать последовательность, но я почти уверен, что в MySQL нет последовательностей.

Первые 2 решения не работают в распределенной среде, поэтому я бы сделал третье.

Да, это, безусловно, склонны к проблемам параллелизма. Одно из предложений - сохранить счетчик в памяти с помощью AtomicInteger, чтобы в конечном итоге вы не всегда получали текущий максимальный идентификатор из БД, что может вызвать состояние гонки. Таким образом, когда приложение запускается, запрашивая БД, оно может сохранить maxId в памяти. Это надежно, даже в случае любого сбоя, он всегда может прочитать информацию из БД.

Это не сработает в распределенной среде, в этом случае, если в комментариях предложено использовать другую таблицу, предназначенную для хранения счетчика, то это лучший подход.

Другие вопросы по тегам