#multithreading #spring-boot #hibernate #jpa
#многопоточность #весенняя загрузка #спящий режим #jpa
Вопрос:
У меня есть счетчик в базе данных, который необходимо обновить, чтобы поддерживать общее количество «загрузок». Этот счетчик будет обновляться каждый раз, когда пользователь загружает файл. Счетчик создается на основе имени файла. Мы создаем новую запись в базе данных, если имени там нет со значением счетчика 1, иначе обновим ее.
В соответствии с развертыванием у нас запущены два экземпляра одних и тех же приложений.
Проблема, с которой я сталкиваюсь, заключается в том, как предотвратить обновление, если один поток уже обновляет / создает его.
Поток 1 :
currentCounter = 1
updateOperation = 1 1 = 2
Поток 2 (в то же время) :
currentCounter = 1
updateOperation = 1 1 = 2
Expected updateOperation = 2 1 = 3
Это будет еще большей проблемой, когда у меня будут запущены два экземпляра.
Ответ №1:
Я предлагаю использовать объект регистрации событий
@Entity
public class EventRegistration {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
String eventName;
LocalDateTime happenedAt;
boolean handled;
@Version
Long version;
public EventRegistration(String eventName) {
this.eventName = eventName;
happenedAt = LocalDateTime.now();
handled = false;
}
public void setAsHandled() {
handled = true;
}
// getters, equals, hascode, toString etc...
}
Вы можете создавать новую запись EventRegistration
для каждого события. Затем обновите счетчик событий по таймеру, добавив количество необработанных EventRegistration
секунд и установив handled = true
или даже удалите обработанные повторные записи
@Autowired
EventRegistrationRepository repository;
@Transactional
public void updateEventCounter(String eventName) {
List<EventRegistration> registrations = repository.getAllByEventNameAndHandled(eventName, false);
//update event counter
registrations.forEach(EventRegistration::setAsHandled);
repository.save(registrations);
}