Программирование обновлений БД в R/3

Транзакция — в информатике, группа последовательных операций, которая представляет собой логическую единицу работы с данными. Транзакция может быть выполнена либо целиком и успешно, с соблюдением целостности данных и независимо от параллельно идущих других транзакций, либо не выполнена вообще, в каковом случае она не должна произвести никакого эффекта. Транзакционность в системе SAP поддерживается на двух уровнях; на уровне СУБД и на уровне сервера приложений:

  • На уровне СУБД транзакционность поддерживается путем открытия ЛЕР (логических единиц работы, английский вариант LUW Logical Unit of Work). В начале выполнения программы при обращении к базе данных открывается ЛЕР на уровне базы данных, далее при работе программы, если происходит явный или не явный COMMIT, то текущий ЛЕР закрывается, все данные сохраняются в БД и открывается новый ЛЕР.

  • На уровне сервера приложений для обеспечения транзакционности используются «модули обновления» (такие как CALL FUNCTION IN UPDATE TASK, PERFORM ON COMMIT), данные модули при вызове регистрируются в системе, но не выполняются сразу. Система собирает очередь обновления, после того, как в программе появляется явный оператор завершения транзакции (COMMIT WORK), система начинает выполнять последовательно зарегистрированные процессы обновления. Если в программе выполняется явный оператор отката транзакции (ROLLBACK WORK), то система удаляет вызовы из очереди обновления и откатывает текущий ЛЕР на уровне БД.

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

  1. Обновление, инициируемое в основном приложении:
  • Прямое обновление
  • Обновление, использующее отложенные вызовы процедур
  1. Обновления, запускаемые программами обновления, со следующими параметрами:
  • Синхронный, асинхронный и локальный запуск
  • Через модули обновлений с типом V1 или V2.

 

Прямое обновление

Прямое обновление подразумевает использование операторов OpenSQL изменяющих состояние базы данных, после чего происходит вызов COMMIT WORK. Программа будет остановлена на операторе COMMIT WORK до тех пор, пока все обновления не выполнятся.

Отложенный вызов процедур обновлений

Отложенный вызов подразумевает собой регистрацию процедур обновления с помощью ключевого слова PERFORM <ИмяПроцедуры> ON COMMIT (ROLLBACK). Запуск этих процедур не происходит сразу, они начинают выполняться только после оператора COMMIT WORK (ROLLBACK). Данные процедуры не должны иметь интерфейса. В случае, если в какой либо зарегистрированной процедуре происходит ошибка, для отмены изменений необходимо вызвать MESSAGE с типом A.  Работа программы возобновляется после того как отработает последняя процедура.

Кроме того отложенные вызовы процедур могут быть использованы в обновлениях запускаемых программой обновления (см. ниже).

Обычно выполнение процедур происходит в том же порядке, в котором они вызваны, однако можно переопределить порядок вызова процедуры с помощью ключевого слова LEVEL <Уровень>. Чем ниже уровень, тем раньше будет запущена процедура.

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

Крайне не рекомендуется использовать одновременно прямые и обновления запускаемые программой обновления, тем более в расширениях системы, где во время работы программы может быть вызван неявный DB COMMIT из-за чего прямые обновления в систему будут записаны, а те что делались программой обновления нет (небыли запущены). Проблемы неявных COMMIT’ов рассмотрена ниже.

Отменить отложенные вызовы, без отмены SAP LUW можно следующим способом:

Обновления, запускаемые программой обновления

Общая схема работы выглядит следующим образом:

Как правило, программа обновления запускается в отдельном рабочем процессе, отдельно от главной диалоговой программы (исключение локальное обновление).  Рассмотрим процесс по шагам:

Шаг 1. Диалоговая программа получает данные от пользователя и заносит их специальную таблицу с запросами на обновление.

Шаг 2. Диалоговая программа завершает свой LUW, инициируя перенос пакета созданных запросов в программу обновления, вызывает оператор COMMIT WORK (AND WAIT).

Шаг 3. На третьем шаге  пакет запросов будет перенесен системой в программу обновления.

Шаг 4. Программа обновления переносит все данные из запросов в базу данных.

Шаг 5. Если программа обновления выполнилась успешно, система удаляет все запросы, связанные с текущим LUW. В случае если происходит ошибка, обрабатываемые записи в таблице помечаются как некорректные. Пользователь, запустивший обновление, получает уведомление на SAP почту. За отправку уведомлений отвечает параметр rdisp/vbmail, за список пользователей параметр rdisp/vb_mail_user_list. Транзакция показывающая запросы обновлений – SM13.

С технической точки зрения, регистрация запросов на обновление происходит с помощью специальных ФМ – модулей обновления. Определяется в свойствах ФМ:

Интерфейс данных функций поддерживает только IMPORTING и TABLES параметры. Параметры EXPORTING и EXCEPTIONS игнорируются и не должны использоваться.

Регистрация запросов на обновление в диалоговой программе происходит с помощью специального вызова ФМ с ключевым выражением – IN UPDATE TASK. Все запросы сохраняются в таблице со специальным ключом VBKEY, который идентифицирует текущий LUW.  Как только вы запустите COMMIT WORK (Шаг 2), будет инициировано обновление (Шаг 3).

Для того чтобы удалить все запросы на обновления можно воспользоваться либо ROLLBACK WORK, либо MESSAGE TYPE A. При этом будут отменены как все запросы на обновления, так и все прямые изменения (если они были, нежелательно), будет создан новый LUW.

В модулях обновления запрещено использование COMMIT WORK или ROLLBACK WORK, но если вы хотите отменить все изменения вносимые запросами, необходимо вызывать MESSAGE TYPE A. После чего все запросы в текущем LUW будут отмечены как ошибочные (тр. SM13), пользователь совершающий обновление будет оповещен об ошибке.

При использовании системы блокировок, если параметр _scope выставлен по умолчанию (2), система снимет все поставленные блокировки (см. статью про блокировки).

Асинхронный запуск модулей обновления

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

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

Асинхронные обновления должны использоваться в программах, где обновление базы данных занимает продолжительное время.

Синхронный запуск модулей обновления

При синхронном запуске модулей обновления необходимо использовать конструкцию COMMIT WORK AND WAIT.

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

Локальные обновления

При локальном обновлении обработка запросов на обновление осуществляется в той же диалоговой программе, где они были зарегистрированы, сами запросы хранятся при этом в области памяти, а не в таблице. Для того чтобы включить локальные обновления необходимо воспользоваться следующим выражением SET UPDATE TASK LOCAL до момента регистрации запросов.  Работа программы возобновляется только после обработки всех запросов текущего LUW, т.о. обновление происходит синхронно, из-за этого локальные обновления применяются в основном в фоновом режиме.

 

Типы модулей обновления

Существует два типа модулей обновления V1 и V2. Тип определяет порядок обработки запросов. Сначала обрабатываются все запросы V1 в своем LUW (в отдельном рабочем процессе, если в системе настроены V2 модули обновления), затем если все V1 запросы были выполнены, запускается обновление V2 запросов в отдельном LUW.

V1 модули могут быть с возможностью повторного запуска и без. Повторить запросы можно через транзакцию SM13. Запросы V2 модулей можно всегда повторить.

Общая схема работы V1 и V2 модулей:

Как видно из рисунка – V1 и V2 запросы обрабатываются в отдельных рабочих процессах. В случае если в системе не настроено использование V2 модулей, они будут выполняться в том же рабочем процессе что и V1, но в разных DB LUW. Следует отметить, что если используются блокировки и параметр _scope стоит по умолчанию (2), в момент запуска обработки V2 запросов все блокировки будут уже сняты.

Стоит обратить особое внимание на то, что при запуске в синхронном режиме ожидание будет происходить только для V1 модулей, система не будет ожидать пока выполнятся V2 модули.

Отложенный запуск процедур обновлений в модулях обновлений

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

Проблемы неявных COMMIT’ов

При обработке программы на сервере приложений системы часто происходит закрытие текущей ЛЕР БД и открытие новой ЛЕР БД в рамках одной программы (неявные COMMIT’ы). Данная ситуация постоянно происходит при обработке экранов. На из справки (ниже) по обновлению системы видно, что при каждой обработке событий PAI на экране происходит неявный DB COMMIT, после чего текущий ЛЕР БД закрывается и открывается новый, и все прямые обновления сделанные в БД больше откатить нельзя. На первый взгляд, что в этом такого, но давайте рассмотрим пример.

Для примера была создана таблица ZTEST_UPDATE в БД

Написана простая программа.

До запуска данной программы таблица была пустая.

После запуска программы из общих соображений ожидается, что таблица так и останется пустой, но это не так. Сообщение выданное в виде окошка, вызывает неявный DB COMMIT и после этого оператор отката ROLLBACK WORK откатывает уже новую ЛЕР, а ЛЕР в которой был сделан MODIFY уже закрыт, и изменения в БД сохранены.

Однако, если убрать оператор MESSAGE (в Программе 1), то таблица так и останется пустой.

Неявные DB COMMIT’ы вызываются в следующих случаях:

  • Смена SAP экрана
  • Вызов диалогового сообщения
  • Оператор Wait прерван рабочим процессом
  • Синхронный или асинхронный вызов RFC функции (исключение qRFC, tRFC, bgRFC)
  • При вызове транзакции CALL TRANSACTION, LEAVE TO TRANSACTION или программы через SUBMIT.

Неявные DB ROLLBACK’и вызываются в следующих случаях:

  • Ошибка времени выполнения
  • Сообщение об ошибке с типом A,X
  • Alexander G.

    Отличная статья, спасибо, выручила!

    • Astrafox

      Спасибо за отзыв, некоторые материалы были позаимствованы из данной статьи: sapland.ru/articles/stats/2010/1/Tonkie_momenti_obnovleniya_bazi_dannih_v_ABAP.html

  • Andron

    Коротко и исчерпывающе! Спасибо!

  • Ильмир Нуриев

    А есть аналог ассинхроного коммита для метода?
    Или проще в метод зашить вызов фм или перформ с соответствующими параметрами?

    • Astrafox

      Реализации отложенных обновлений для методов не существует.