Как вы управляете одновременным доступом к формам? - PullRequest
14 голосов
/ 25 августа 2010

В нашем веб-приложении есть набор форм, который управляется несколькими сотрудниками. Формы являются общими для всех сотрудников. Прямо сейчас мы реализовали механизм блокировки. Но проблема в том, что нет надежного способа узнать, когда пользователь вышел из системы, поэтому форму необходимо разблокировать. Мне было интересно, есть ли лучший способ управлять одновременными пользователями, редактирующими одни и те же данные.

Ответы [ 8 ]

13 голосов
/ 26 августа 2010

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

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

Update Table set column = changedvalue 
where column1 = column1prev 
AND column2 = column2prev...

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

Вы также можете создать логику повторных попыток?Перечитайте строку из базы данных и проверьте, можно ли безопасно объединить изменения, сделанные вашим пользователем, и изменения, внесенные в базу данных, а затем сделать это автоматически.Или вы могли бы предоставить пользователю выбор относительно того, хотят ли они по-прежнему вносить свои изменения, основываясь на значениях, находящихся сейчас в базе данных.

5 голосов
/ 31 августа 2010

Как предположил Спенс, вам нужен оптимистичный параллелизм.Стандартный веб-сайт, который не учитывает, изменились ли данные, использует то, что я называю «последние записи выигрывают».Проще говоря, независимо от того, какое соединение сохраняется в базе данных последним, эта версия данных остается неизменной.В оптимистическом параллелизме вы используете логику «первая запись выигрывает», так что если два соединения пытаются сохранить одну и ту же строку одновременно, первое, которое фиксирует выигрыш, а второе отклоняется.

Этот механизм состоит из двух частей:

  1. Правила, по которым вы не выполняете второй коммит
  2. Как система или пользователь обрабатывают отклоненный коммит.

Определение отклонения фиксации

Два подхода:

  1. Столбец сравнения, который изменяется каждый раз, когда происходит фиксация
  2. Сравнить данныес его подтвержденной версией в базе данных.

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

Второй - сравнение столбцов, которые вы извлекли, с их существующими значениями фиксации в базе данных.,Как предположил Спенс, если вы попытаетесь обновить и ни одна строка не будет обновлена, то очевидно, что один из критериев не выполнен.Эта логика может стать хитрой, когда некоторые значения равны нулю.Многие объектно-реляционные сопоставители и даже технологии .NET DataTable и DataAdapter могут помочь вам справиться с этим.

Обработка отклоненного коммита

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

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


Концепция извлечения - это эффективно пессимистичный параллелизм, когда пользователи "блокируют" строки.Как вы обнаружили, это трудно реализовать в среде без состояния.Пользователи печально известны тем, что просто закрывают свой браузер, когда они что-то извлекли, или используют кнопку «Назад», чтобы вернуть проверенный набор и попытаться повторить его.ИМО, это больше проблем, чем стоит пытаться пойти по этому пути в веб-решении.Предполагая, что вы пишете имя пользователя, которое в последний раз изменило данную строку, с оптимистичным параллелизмом, вы можете сообщить пользователю, отклоненные изменения которого сохранили данные перед ними.

5 голосов
/ 29 августа 2010

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

Если второе изменение отличается от первого, запись сейчас находится в конфликте. Пользователю предоставляется новая форма, которая указывает, какие поля были изменены в результате конфликтующего обновления. В этом случае пользователь несет ответственность за разрешение конфликта (путем обновления обоих наборов изменений) или за сохранение существующего обновления.

1 голос
/ 25 августа 2010

Я видел, как это делалось двумя способами. Во-первых, в таблице базы данных должен быть столбец «извлечен», связанный с этими данными. Ваша служба должна искать этот флаг, чтобы увидеть, редактируется ли он. Это может истечь после истечения порога времени (с триггером), если пользователь не фиксирует изменения. Второй способ - это выделенная «извлеченная» таблица, в которой хранятся идентификаторы и имена объектов (возможно, имя таблицы). Это будет работать так же, и теоретически у вас будет меньше времени на поиск. Однако я вижу проблемы с параллелизмом при использовании второго метода.

0 голосов
/ 03 сентября 2010

Самый простой способ - отформатировать оператор обновления, чтобы включить дату и время последнего обновления записи. Например:

UPDATE my_table SET my_column = new_val WHERE last_updated = <datetime when record was pulled from the db>

Таким образом, обновление завершается успешно, только если никто не изменил запись с момента последнего чтения.

Вы можете отправить пользователю сообщение о конфликте, проверив, было ли обновление выполнено с помощью SELECT после ОБНОВЛЕНИЯ.

0 голосов
/ 03 сентября 2010

Вы можете использовать столбец «timestamp» в вашей таблице. См. Что такое загадочный тип данных 'timestamp' в Sybase?

Я понимаю, что вы хотите избежать перезаписи существующих данных последовательными обновлениями.

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

После изменения данных непосредственно перед обновлением, вы должны проверить столбцы «timestamp» (ваши и db), чтобы убедиться, что кто-то изменил данные во время редактирования.

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

0 голосов
/ 31 августа 2010

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

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

Это очень просто и работает достаточно хорошо.

0 голосов
/ 26 августа 2010

Зачем вам нужно искать время ожидания сеанса? Просто синхронизируйте доступ к вашим данным (формы или что-то еще) и все.
ОБНОВЛЕНИЕ: Если вы имеете в виду «длинные транзакции», когда форма блокируется, как только пользователь открывает редактор (или что-то еще), и остается заблокированной, пока пользователь не примет изменения, тогда:

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