ABAP Object Services — Интеграция с системой блокировок

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

К сожалению, в ABAP Object Services нет встроенного механизма поддержки блокировок, что может привести к ошибкам и противоречивости данных при одновременном изменении одинаковых объектов.

Далее в ходе статьи мы разберем один из способов интеграции с системой блокировок.

Но прежде чем рассматривать механизм интеграции, необходимо отметить следующее:

  • При использовании системы блокировок, программисты должны позаботиться о том, чтобы заблокированный объект был, как можно быстрее разблокирован.
  • За установку и снятие блокировок, прежде всего, отвечает разработчик, но снятие блокировок может происходить и автоматически, данный аспект следует учитывать при интеграции с хранимыми объектами. Так если при выставлении блокировки был указан параметр _SCOPE= 2, система может автоматически снимет все блокировки при завершении транзакции верхнего уровня через метод UNDO или при вызове ROLLBACK WORK в режиме совместимости.  Если транзакция верхнего уровня была завершена методом END, либо в режиме совместимости был вызван оператор COMMIT WORK, система снимет блокировки только в том случае, если был зарегистрирован хотя бы один модуль обновления (V1). Transaction Service регистрирует модуль обновления, если не было указано что обновления необходимо производить напрямую (direct update) и если хранимый объект был изменен (по умолчанию, касается только изменения хранимых атрибутов).  Если вы используете прямое обновление или хранимый объект не изменялся, при выставленном параметре _SCOPE = 2, блокировки снимаются при завершении SAP LUW, либо принудительно через модуль разблокирования DEQUEUE_*.

Пессимистичные и оптимистичные блокировки

Существует две основные стратегии блокирования: пессимистичная и оптимистичная. Стратегия, в данном случае, определяет порядок действий, выполняемых при блокировании и разблокировании объектов, а также поведение системы при обработке объектов блокировки.

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

Для того чтобы иметь возможность редактировать объект и быть уверенными в том, что блокировка установлена в классе агенте мы реализуем следующий метод:

lock_and_get_persistent

В методе присутствует входной параметр iv_enqueue_mode, внутри которого будем указывать стратегию блокировки, используемую для загружаемого объекта:

  • «Е» — пессимистичная стратегия
  • «О» — оптимистичная стратегия

Внутри метода происходит повторная загрузка хранимого объекта из БД и вызов модуля установки блокировки.

Благодаря параметру _scope = ‘3’ мы точно будем уверены в том, что блокировка не будет снята автоматически.

Так же был добавлен свой класс исключения zcx_os_object_not_blocked, данный класс уведомляет нас о невозможности продолжения работы с объектом из-за ошибки при выставлении блокировки. Подробнее о классах исключений смотрите тут. В классе исключения определен текст внутри которого выводится переданный в параметрах исключения text:

zcx_os_object_not_blocked_text

zcx_os_object_not_blocked2

Все заблокированные нашей программой объекты будут храниться в атрибуте класса агента с табличным типом TYP_BUSINESS_KEY_TAB:

gt_locks

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

Тестовая программа, выводящая ошибку, в случае невозможности блокирования объекта (объект уже заблокирован эксклюзивной блокировкой):

Результат обработки исключения:

TestProgram

Следующий шаг после изменения полученного объекта определяется в зависимости от стратегии блокировки, для пессимистичной стратегии необходимо чтобы после сохранения данных объекта в БД, выставленные ранее блокировки были сняты.

Для этого в классе агенте создан специальный метод снятия блокировки:

unlock_object

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

Для оптимистичной стратегии блокирования необходимо до момента запроса на сохранение в БД, преобразовать выставленную ранее блокировку в эксклюзивную. Создадим в классе агенте следующий метод преобразования:

convert_lock

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

check_enqueue

После успешного преобразования может быть вызван COMMIT WORK или метод транзакции END. Закончив сохранения объекта в БД, можно вызвать снятие блокировок через метод рассмотренный ранее.

Описанная в данной статье схема интеграции с системой блокировок является лишь одной из возможных, в качестве альтернативной можно использовать автоматическое выставление блокировок до момента загрузки хранимого объекта из БД, делается это через переопределение метода в классе агенте: MAP_LOAD_FROM_DATABASE_KEY — если бизнес ключ на основе ключевых полей таблицы, MAP_LOAD_FROM_DATABASE_GUID – если бизнес ключ на основе GUID.

Можно так же автоматически снимать блокировки через агента проверки консистентности (класс реализующий интерфейс IF_OS_CHECK) хранимого объекта, но подобная автоматизация возможна только для ООП транзакций, т.к. исключения выдаваемые в агентах проверки невозможно обработать в транзакциях в режиме совместимости.

Подробнее об альтернативной схеме интеграции с системой блокировок можете прочитать в книге: Object Services in ABAP.

  • Sergey

    Спасибо! Все очень доходчиво.

    • Astrafox

      Пожалуйста!