[безжалостно skipped]
AK>Что pessimistic, что optimistic — такая реализация одновременного доступа только лишь с помощью транзакций не позволяет "спокойно" работать с такой простейшей базой данных, которая приведена в моем примере. У нас в сети всего три (очень редко четыре) компьютера, и между ними иногда происходят конфликты, связанные с одновременным доступом. Правильно, или ты ждешь неизвестно сколько, пока запись не освободится, или ты получаешь откат после вдумчивого редактирования накладной с пояснением, что ты не имеешь, оказывается, право эту накладную редактировать.
AK>Пришлось искать какой-то выход из положения. Ничего лучшего не придумав, в базу данных пришлось ввести служебную таблицу (назовем ее условно LOCKER), которая содержит в себе все имеющиеся на данный момент блокировки. Она выглядит примерно так:
AK>User Table Info(номер блокированного документа) AK>================================================================= AK>1 INVOICE 56 AK>1 ORDER 12 AK>2 INVOICE 55 AK>3 INVOICE 57
AK>итак, пользователь 1 зашел в накладную 56. При этом он может редактировать эту накладную, либо пить кофе в другой комнате (что тоже иногда встречается). Пользователь N, заходя в накладную 56, получает информацию из таблицы LOCKER, что накладная 56 заблокирована пользователем 1. Он может читать из накладной 56 информацию, но никогда не начнет ее бесполезное редактирование. Как только пользователь 1 ушел с накладной 56, в таблице LOCKER исчезла эта строка("1 INVOICE 56") и накладная свободна для других пользователей. Вот в моменты записи/чтения в таблицу LOCKER транзакции просто доктор прописал — эти моменты столь кратковременны, что пессимистичная блокировка не видна для пользователей.
AK>Иначе — бесконечные непонятки между пользователями.
Все правильно! Таким образом, вы реализовали чистейшей воды Pessimistic Locking. Таблица LOCKER используется как менеджер локов.
Недостатоки такого подхода:
— все приложения обязаны быть "вежливыми" и не забывать посмотреть в эту таблицу.
— если пользователь заблокировал накладную, пошел пить кофе, отравился и умер, то накладная останется заблокированной навсегда.
Достоинтство: Легким движением руки можно добавить возможность административного вмешательства. Например, менеджер или там администратор может "сломать" замок, поставленный нерадивым пользователем.
Теперь о том, как все это можно было бы сделать поверх базы данных, которая поддерживает pessimistic locking:
0. Мы отключаем ожидание разблокирования по умолчанию
1. Когда мы открываем накладную, мы ставим на нее shared lock (в случае неудачи сразу сообщаем пользователю, что прямо сейчас кто-то пишет)
2. Когда пользователь пытается начать редактирование, мы переводим shared lock в update lock. Если нам это не удается, значит кто-то уже начал редактирование.
3. Теперь полоьзователь долго и вдумчиво редактирует накладную. Все могут спокойно читать, но пункт 2 никто из них не пройдет.
4. Наконец, пользователь давит "сохранить". В этот момент мы пытаемся получить exclusive lock, и нам придется подожлать, пока все дочитают. Но нам точно известно, что именно мы получим возможность записать данные, а не кто-то другой.
5. Все, запись удалась, можно жить дальше.
Возможная модификация: для чтения мы получаем shared lock и сразу же его отпускаем, чтобы не создавать другим задержек на шаге 4. При выполнении шага 2 мы перечитываем данные, чтобы учесть возможные изменения, произошедшие между 1 и 2.
Преимущество такого подхода в том, что мы защищены от негодяев средствами сервера. Во-первых, он не даст нарушить блокировку никому другому, даже если он ничего не знает про наши соглашения. Во-вторых, если клиентская программа упала, то все блокировки будут автоматически отпущены.
Как реализовать подобное поведение средствами MS SQL Server я знаю — нужно всего лишь покопаться в настройках lock timeout, и применять некоторое шаманство с set transaction isolation level или хинтами в select-ах. Насчет других серверов пришлось бы покопать доки пару дней.
Если интересны подробности реалтзации такого щастья для MSSQL — могу написать. Кстати, можно даже отловить, кто именно нас заблокировал (в смысле идентификатор пользователя), и, если применяется WinNT Autentification, то послать ему мессагу через Messenger Service.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.