Блокировка записей
Когда вы читаете записи из таблицы базы данных, AVM применяет к записи уровень блокировки, которым вы можете управлять, чтобы предотвратить конфликты, когда несколько пользователей одних и тех же данных пытаются одновременно читать или изменять одни и те же записи. Эта блокировка не применяется к временным таблицам, поскольку они строго локальны для одной сессии ABL и никогда не используются совместно между сессиями. Существует три уровня блокировки:
- NO-LOCK— это параметр только для чтения, который может считывать неполные транзакционные данные.
- SHARE-LOC – удерживается до окончания транзакции или освобождения записи, в зависимости от того, что наступит позже.
- EXCLUSIVE-LOCK – удерживается до окончания транзакции. Затем преобразуется в SHARE-LOCK, если область записи больше, чем транзакция, и запись все ещё активна в любом буфере. Лучше всего явным образом освободить запись после завершения изменения.
Когда вы читаете записи с помощью оператора FIND, блока FOR EACH или оператора запроса GET, по умолчанию запись читается с блокировкой SHARE-LOCK. Другой пользователь также может прочитать ту же запись, используя другой блокировку SHARE-LOCK.
Вы можете читать записи, используя другой уровень блокировки. Если вы собираетесь изменить запись, вы можете использовать ключевое слово EXCLUSIVE-LOCK. В этом случае запись помечается как зарезервированная для вашего исключительного использования. Если какой-либо другой пользователь имеет запись с SHARE-LOCK, попытка прочитать её с EXCLUSIVE-LOCK завершится ошибкой. Таким образом, SHARE-LOCK гарантирует, что, хотя другие пользователи могут прочитать ту же запись, что и вы, они не могут её изменить. Такую запись также можно прочитать, используя NO-LOCK.
Когда транзакция отменяется, блокировки, полученные в рамках транзакции, снимаются или изменяются на SHARE-LOCK, если с ней были заблокированы до транзакции.
Оптимистическая блокировка
В традиционном хост-приложении или клиент-серверном приложении можно применить то, что называется пессимистичной стратегией блокировки. Это означает, что ваше приложение всегда получает EXCLUSIVE-LOCK, когда оно впервые читает любую запись, которая может быть изменена, чтобы гарантировать, что ни один другой пользователь не попытается обновить ту же запись.
В распределённом приложении этот приём не работает. Если вы читаете и передаёте записи в сессию клиента, ваша сессия на стороне сервера не может легко удерживать блокировки записей, пока клиент их использует. Когда процедура на стороне сервера завершается и возвращает временную таблицу записей клиенту, буферы записей на стороне сервера выходят за пределы области действия, а блокировки снимаются. Кроме того, вы не должны поддерживать блокировки записей в течение длительного периода времени, так как это может привести к конфликту записей.
Лучший способ убедиться, что вы получаете желаемую блокировку, — это чётко указать её. Следуйте следующим двум рекомендациям по использованию блокировок:
- Всегда начинайте транзакцию перед началом чтения записей, даже с NO-LOCK, если вы собираетесь изменять их внутри транзакции.
- Освобождайте записи явно, когда вы закончите их изменение, с помощью инструкции RELEASE.
В следующем примере показано, как сначала получить запись из таблицы Customer с помощью NO-LOCK, а затем извлечь её с использованием EXCLUSIVE-LOCK.
VAR ROWID custrid. FIND FIRST Customer NO-LOCK WHERE Customer.Balance > 1000. /* Get the rowid and save it, so it can be refetched. */ custrid = ROWID(Customer). IF balance > 0 THEN DO TRANSACTION: FIND Customer WHERE ROWID(Customer) = custrid EXCLUSIVE-LOCK. /* Update the Comments field in the Customer record */ Customer.Comments = "Balance remaining". DISPLAY Customer.Name Customer.Balance Customer.Comments FORMAT "X(20)". RELEASE Customer. END.
Дополнительные сведения см. в разделе «Обработка данных и блокировка записей».