2014-09-11 1 views
1

У меня есть веб-сервис и пара асинхронных служб, работающих на фоновом режиме (для длительных процессов сбора данных), которые используют ту же библиотеку DAO и общий источник данных. Библиотека DAO реализована с использованием шаблона Spring JDBC. RDBMS - PostgreSQL.
Это редко случается, когда веб-служба и асинхронные службы одновременно изменяют одни и те же строки в одной таблице через DAO, и в результате я получаю несогласованные данные.
Например, у меня есть поле «state» в сущности, которая может принимать значение: 1 - платный, 2 - неоплаченный.

Иногда у меня такие ситуации:Как справиться с одновременной модификацией изменений данных и слиянием в веб-службе (оптимистичный/пессимистический блокировка)?

  • сделка # 1: Веб-служба изменяют "состояние" значение от 1 до 2 к строке с ID = 1.
  • транзакции # 2: В то же время асинхронная служба захватывает некоторые данные с некоторых конечных точек и модифицирует другие поля строки с идентификатором = 1. Но удержание поля «состояние» 1. Оно не знает, что значение «состояние» было изменено с 1 до 2 в транзакции № 1.

В результате у меня «состояние» равно 1, хотя оно должно быть 2. Оно также работает противоречиво. Несколько раз асинхронная служба меняет поле «состояние», и веб-служба не знает об этом изменении и снова создает беспорядок в данных. Это происходит не только с полем государства, конечно.

У меня есть два варианта:

  1. Используйте пессимистический SELECT ... FOR UPDATE.
    Но он не подходит для меня , потому что веб-сервис очень часто получает части строк из таблицы. Он не может ждать длительного периода времени, пока асинхронный сервис удерживает блокировки, потому что производительность здесь критическая.
  2. Используйте оптимистичную блокировку. Поле «Версия» и т. Д.
    Но я не могу просто откат изменений в случае оптимистической блокировки, потому что это изменение необходимо объединить. Несколько раз я не могу просто повторить операцию из-за атомных операций в других системах, которые не являются частью весенней транзакции jdbc.

Может быть, существуют некоторые шаблоны для обработки таких случаев, чтобы объединить данные?

Спасибо,
Ивана

+0

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

ответ

2

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

  • внутри одной транзакции (и у меня есть одну единственная операция записи для каждого запроса): пессимистическая блокировка, потому что все такие сделки короткие (они действительно должны быть), и поэтому задержка для получения блокировки является приемлемой и лучше, чем (*)
  • между двумя различными процессами обработки запросов (GET, чтобы показать форму и POST/PUT, которая ее отправляет): оптимистическая блокировка, потому что я не хочу сохранять истинные блокировки базы данных в течение длительного периода времени

Это довольно простой, последовательный, и я только переосмысливаю об этом, если вещи действительно идут не так.

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

(*) Если вы получаете исключение с оптимистическим блокированием, вам необходимо отменить транзакцию, и либо вы можете просто сообщить об ошибке, либо вам придется повторять ее несколько раз.

EDIT:

Если я правильно понял, ваша проблема в том, что у вас есть один длинный бега пакетной обработки и коротких запросов веб-служб.

ИМХО есть три пути решения, но в настоящее время не достаточно информации, чтобы выбрать лучший для случая использования

  • использовать много коротких сделок в вашей партии. Таким образом, вы можете использовать оптимистические блокировки (с повторением), если вероятность одновременных обновлений низкая или пессимистичная блокировка, если у вас не слишком много одновременных запросов веб-сервисов. Это самый простой способ, но не может быть использован, если ваши бизнес-правила требуют, чтобы пакет использовал одну транзакцию.
  • использовать пессимистические блокировки в пакетных и веб-сервисах, но с небольшим тайм-аутом для части веб-сервиса. Таким образом, если вы приобретете блокировку в веб-службе, вы уверены, что никакая партия не модифицирует одно значение и может безопасно совершить. Когда у вас есть блокировка в пакетном режиме, вы уверены, что веб-служба не изменит значение до фиксации. И если веб-служба не может получить блокировку, просто верните ошибку вызывающему. Единственное требование заключается в том, что клиент веб-службы может повторить свой запрос позже.
  • не выполняет транзакции, передаваемые веб-службами, но ставит их в очередь и обрабатывает их все в конце пакетной операции. Таким образом, вы уверены, что веб-службы немедленно возвращаются и что одновременное обновление не может произойти. Но вы должны предоставить механизм, позволяющий клиенту веб-службы позже консультироваться с результатом своих запросов, если они могут быть отклонены, и в любом случае он предполагает, что запросы могут быть отложены. Это отлично работает для депозитов банковских счетов, требует обратной связи для поиска и не может использоваться для бронирования мест в самолете.
+0

Спасибо за ответ. Как я уже писал, проблема сложнее, чем выбор между оптимистическим и пессимистичным блокированием. Попробуйте объяснить в примере. Асинхронная служба начинает работать и выбирает из базы данных партии строк. Затем он вызывает некоторые веб-службы, чтобы получить некоторые данные, чтобы обогатить эти строки. Звонки веб-сервисов занимают много времени. И после всех обновлений служба сохраняет строки. У меня длительная транзакция здесь, и вызовы сторонних веб-сервисов не являются частью транзакции. Если я повторю эти вызовы, я получу дублирование данных в сторонних системах. – Ivan

+0

@Ivan: Oups Я не заметил его сначала, но похоже, что ваша проблема заключается в следующем: у вас есть * на той же базе данных * модификации, которые могут исходить от веб-сервисов с короткими транзакциями и из партий с длительными транзакциями. Можете ли вы подтвердить это, и да, скажите, как долго выполняются партии? –

+0

Да, я подтверждаю. У меня есть 2 проблемы: 1) У меня есть 3 асинхронных сервиса, которые периодически или последовательно обновляют строки в одной таблице, используя сторонние сервисы каждый день и достаточно часто параллельно. Интервал между выборами строк и их обновлением слишком велик. От 10 секунд до 10 минут из-за очень медленного взаимодействия с сторонними службами. 2) Платежные операции, которые несколько раз изменяют состояние строк в одной таблице. Кажется, что первое решение будет хорошо для меня, я попробую. Благодарю. – Ivan

0

Go с оптимистической блокировкой .. И не откат, когда обновление не удается из-за несовпадения версий .. Вместо этого повторить, пока не удается. У вас может быть верхний предел для количества попыток.

+0

Если вы не используете точку сохранения, откат транзакции является единственным вариантом, который у вас есть в Postgres. Как только произошла ошибка в транзакции, вы не можете «просто продолжить» –

+0

Я не могу просто откат. Например. Служба A выберите несколько строк и обработайте их каким-то длительным процессом с периодичностью обновлений для строк в конце.Между тем служба B выполняет оплату за одну из этих строк, которые уже обслуживает A. Теперь у нас есть ситуация, когда служба B изменила состояние от неоплаченных до платных и фиксации изменений в базе данных, но служба B не знает об изменениях и просто переопределит состояние от платного до неоплаченного, когда оно совершит свои собственные изменения. Обе службы используют сторонние службы, и я не могу повторить операции снова. Мне нужно какое-то слияние. – Ivan

Смежные вопросы