Как заблокировать выбор и снять блокировку после обновления, выполненного с использованием Spring? - PullRequest
0 голосов
/ 27 февраля 2019

Я начал использовать весну с последних нескольких месяцев, и у меня есть вопрос по сделкам.У меня есть метод Java внутри моего весеннего пакетного задания, который сначала выполняет операцию выбора, чтобы получить первые 100 строк со статусом «НЕ ЗАВЕРШЕНО», и выполняет обновление выбранных строк, чтобы изменить статус на «В ПРОЦЕССЕ».Поскольку я обрабатываю около 10 миллионов записей, я хочу запустить несколько экземпляров моего пакетного задания, и каждый экземпляр имеет несколько потоков.Для одного экземпляра, чтобы убедиться, что два потока не извлекают один и тот же набор записей, я сделал мой метод синхронизированным.Но если я запускаю несколько экземпляров моего пакетного задания (несколько JVM), существует высокая вероятность того, что оба экземпляра могут получить один и тот же набор записей, даже если я использую «оптимистическую» или «пессимистическую блокировку» или «выбрать для обновления», так какмы не можем заблокировать записи во время выбора.Ниже приведен пример.Транзакция 1 выбрала 100 записей, и тем временем Transaction2 также выбрала 100 записей, но если я включаю блокировку, транзакция 2 ждет, пока транзакция 1 не будет обновлена ​​и зафиксирована.Но транзакция 2 снова делает то же самое обновление.

Можно ли весной выполнить операцию выбора транзакции 2, чтобы дождаться завершения выбора транзакции 1?

Transaction1        Transaction2
fetch 100 records   
                    fetch 100 records
update 100 records



 commit         
                    update 100 records
                    commit



@Transactional
public synchronized List<Student> processStudentRecords(){
List<Student> students = getNotCompletedRecords();
if(null != students && students.size() > 0){
    updateStatusToInProgress(students);
}
return student;
}

Примечание: я не могу сначала выполнить обновление, а затем выбрать.Буду признателен, если будет предложен альтернативный подход?

1 Ответ

0 голосов
/ 28 февраля 2019

Синхронизация транзакций должна быть оставлена ​​серверу базы данных и не управляться на уровне приложения.С точки зрения сервера базы данных, независимо от того, сколько у вас JVM (потоков), это параллельные клиенты базы данных, запрашивающие операции чтения / записи.Вам не следует беспокоиться о таких проблемах.

Что вам следует сделать, так это постараться максимально уменьшить конфликт при разработке вашего решения, например, с помощью (удаленного) метода разбиения.

, если я запускаю несколько экземпляров моего пакетного задания (несколько JVM), существует высокая вероятность того, что оба экземпляра могут быть получены одним и тем же набором записей, даже если я использую «оптимистический»или «пессимистическая блокировка» или «выбрать для обновления», так как мы не можем заблокировать записи во время выбора

Разделение данных по проекту устранит все эти проблемы.Если вы предоставляете каждому экземпляру набор данных для работы, нет никаких шансов, что работник выберет одну и ту же из записей другого работника.Майкл привел подробный пример в этом ответе: https://stackoverflow.com/a/54889092/5019386.

(логическое) Однако разбиение на разделы не решит проблему конфликта, поскольку все работники будут читать / записывать из / в одну и ту же таблицу, ноэто характер проблемы, которую вы пытаетесь решить.Я хочу сказать, что вам не нужно начинать блокировать / разблокировать таблицу в вашем дизайне, оставьте это для базы данных.Некоторые серверы баз данных, такие как Oracle, могут записывать данные одной и той же таблицы в разные разделы на диске для оптимизации одновременного доступа (что может помочь при использовании разбиения), но опять же это бизнес Oracle, а не Spring (или любой другой фреймворк).

Не каждый может позволить себе Oracle, поэтому я бы искал решение на концептуальном уровне.Я успешно использовал следующее решение (физическое разбиение "Pseudo") для решения проблемы, подобной вашей:

  • Шаг 1 (в последовательном режиме): копировать / разбивать необработанные данные во временные таблицы (в последовательном)
  • Шаг 2 (параллельно): запустить несколько рабочих над этими таблицами вместо исходной таблицы с миллионами строк.
  • Шаг 3 (последовательно): скопировать / обновить обработанные данные обратно в исходныйтаблица

Шаг 2 устраняет проблему конфликта.Обычно стоимость (Шаг 1 + Шаг 3) пренебрежимо мала по сравнению с Шагом 2 (еще более пренебрежима, если Шаг 2 выполняется последовательно).Это хорошо работает, если обработка является узким местом.

Надеюсь, это поможет.

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