Централизованная база данных: несколько потребителей - PullRequest
2 голосов
/ 07 июля 2011

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

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

Я вижу 2 возможных способа ее решения, но не уверен:

  1. Еще одно приложение, которое получитзапросы от пользовательских приложений и предоставление им уникальных необработанных записей,
  2. Реализация некоторой хранимой процедуры в базе данных ...

Пожалуйста, сообщите ..

Ответы [ 4 ]

3 голосов
/ 07 июля 2011

Чтобы извлечь строку, создайте хранимую процедуру, которая:

  • запускает транзакцию
  • выбирает и блокирует доступную строку
  • обновляет столбецстрока, помечающая ее как недоступную для других
  • фиксирует транзакцию
  • передает строку клиенту

Чтобы обновить строку, создайте хранимую процедуру, которая:

  • начинает транзакцию
  • обновляет строку (дополнительно проверяет версию строки)
  • обновляет доступность строки
  • фиксирует транзакцию

Дополнительно:

  • вы можете добавить дату / время в строку, чтобы вы знали, когда строка была заблокирована
  • , если строка былазаблокирован на долгое время (дольше, чем вы ожидали), вы можете снять блокировку и позволить кому-то еще выбрать строку.Однако, чтобы не допустить обновления предыдущего владельца (он не знает, что потерял блокировку), в таблице должен быть столбец версии строк.
  • Вы можете сохранить (не) доступный статус в отдельной таблице, котораяможет упростить поиск доступных строк.
1 голос
/ 07 июля 2011

Различные варианты:

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

, однако, лично есть другие метафоры хранения, которые хорошо работают здесь, например, у "redis" есть несколько подходящих операций:

  • RPOPLPUSH (перемещает 1 запись между списками и возвращает ее)
  • SPOP (удаляет и возвращает 1 случайную запись)
  • RPOP / LPOP (удаляет и возвращает 1 запись из конца списка)

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

0 голосов
/ 07 июля 2011

Вы запрашиваете поведение базы данных по умолчанию. Вы можете использовать «SELECT ...... FOR UPDATE», и ядро ​​базы данных заблокирует строку и сделает ее недоступной для других пользователей. Однако это хорошая практика, если ваша программа хочет хранить данные в течение короткого промежутка времени (менее 1 секунды), и ваше приложение, которое хранит данные гораздо дольше, столкнется с множеством проблем взаимоблокировки и конфликтов.

Вы можете сделать это в коде приложения, имея пару столбцов, таких как "RESERVED_BY_USER" и "RESERVED_UNTIL", которыми приложения могут управлять сами.

Однако из того, что вы описываете, я думаю, что вам действительно нужна очередь, как описано здесь

0 голосов
/ 07 июля 2011

Добавьте еще одно поле в таблицу с помощью ProcessedBy, и вы можете установить значение в null, если ни одна машина не была запущена, и установить значение на имя машины, если оно начало обработку.При получении записи вы можете проверить это поле обрабатываются, а если оно пустое, вы можете назначить его любому компьютеру.

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