Неожиданная фиксация базы данных при отображении данных с использованием cl_salv_table - PullRequest
4 голосов
/ 29 марта 2019

В программе ABAP я заметил неожиданное сохранение данных при отображении локальной таблицы с использованием класса cl_salv_table.

Для воспроизведения я создал минимальный пример кода. Программа выполняет вставку, отображает данные в формате ALV, затем выполняет ROLLBACK WORK. Я ожидаю, что вставленное значение будет присутствовать в базе данных ДО отката, и отсутствует ПОСЛЕ отката.

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

Это ожидаемое поведение, и если так, как я могу избежать этого? Мы используем этот класс довольно часто, и похоже, что мы можем непреднамеренно зафиксировать значения в базе данных, когда на самом деле этого не хотим.


Это код:

*&---------------------------------------------------------------------*
*& Report  zok_alv_commit
*&
*&---------------------------------------------------------------------*
*&
*&
*&---------------------------------------------------------------------*
REPORT zok_alv_commit.

SELECTION-SCREEN BEGIN OF BLOCK b1.

PARAMETERS: p_showtb TYPE boolean AS CHECKBOX DEFAULT abap_false.

SELECTION-SCREEN END OF BLOCK b1.

START-OF-SELECTION.

  DATA: lt_table TYPE TABLE OF zok_alv,
        ls_table TYPE zok_alv.

  """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
  " Create new GUID and insert into table
  """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
  TRY.
      ls_table-guid = cl_system_uuid=>create_uuid_c22_static( ).
    CATCH cx_uuid_error.
      " Error creating UUID
      MESSAGE e836(/basf/dps3_apodata).
  ENDTRY.
  WRITE: |Create guid { ls_table-guid } |, /.

  INSERT zok_alv FROM ls_table.
  APPEND ls_table TO lt_table.

  """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
  " The important bit: show something in an ALV
  """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

  IF p_showtb = abap_true.
    cl_salv_table=>factory(
      IMPORTING r_salv_table = DATA(lo_alv)
      CHANGING t_table = lt_table
    ).

    lo_alv->display( ).
  ENDIF.

  """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
  " Check existence in table before and after rollback
  " Expectation: If the ALV is shown above, the data is already committed,
  " so the ROLLBACK WORK will not have an effect.
  """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

  SELECT SINGLE guid FROM zok_alv INTO @DATA(lv_ignored) WHERE guid = @ls_table-guid.
  IF sy-subrc = 0.
    WRITE: 'GUID exists on DB before rollback.', /.
  ELSE.
    WRITE: 'GUID does NOT exist on DB before rollback.', /.
  ENDIF.

  ROLLBACK WORK.

  SELECT SINGLE guid FROM zok_alv INTO @lv_ignored WHERE guid = @ls_table-guid.
  IF sy-subrc = 0.
    WRITE: 'GUID exists on DB after rollback.', /.
  ELSE.
    WRITE: 'GUID does NOT exist on DB after rollback.', /.
  ENDIF.

Требуется таблица ZOK_ALV с только MANDT и 22-символьным полем GUID в качестве первичного ключа, ничего больше.


При выполнении кода с p_showtb не проверено :

Selection screen 1 Result screen 1 Table view 1

Как видите, значение отсутствует после отката и не отображается в таблице - как ожидалось.

При выполнении кода с p_showtb проверено :

Selection screen 2 ALV screen

На этом этапе идентификатор SE16 уже виден в другом сеансе:

Table view 2

(я оставляю экран ALV с Back (F3) на этом этапе) Код подтверждает, что значение сохраняется, даже после отката:

Result screen 2

Даже после выхода из программы значения сохраняются в БД.

Ответы [ 2 ]

6 голосов
/ 30 марта 2019

Чтобы ответить на 2 вопроса:

1) Да, это «ожидаемое поведение» , как указано в документации о фиксации базы данных :

фиксация базы данных выполняется неявно в следующей ситуации: Завершение шага диалога ...

(это означает, что любое отображение выполняет фиксацию базы данных)

Это связано с тем, что при отображении экрана SAP ничего не делает, кроме ожидания действия пользователя, поэтому рабочий процесс , который использовался для выполнения кода ABAP до отображения, можно повторно использовать для выполнение ABAP-кода запросов от других пользователей.

Чтобы рабочий процесс можно было повторно использовать, память рабочего процесса (переменные) должна быть переключена, это называется roll-out / roll-in , что также требует, чтобы некоторые системные таблицы базы данных были обновляется для внутреннего содержимого SAP, и для этого требуется фиксация базы данных. Это лучше объясняется в документации SAP LUWs . Я где-то читал, но точно не помню, где.


2) Нет, вы не можете "избежать этого поведения" , но, учитывая текущую логику вставки + отображения + отката вставки, вы можете сделать одно из этих решений, но я рекомендую только первое один в вашем случае, а не второй:

  • Измените свою логику, чтобы она соответствовала правилу SAP (т. Е. Любое отображение выполняет фиксацию базы данных, поэтому имейте это в виду). Если ваша логика действительно та, которую вы сказали, то почему вы хотите вставить что-то в базу данных и выполнить откат? Без дальнейших подробностей, мой ответ - просто удалить вставку и откат и сохранить отображение. Было бы чистым предположением ответить на что-то еще, потому что вы не дали достаточно подробностей о том, как на самом деле работает ваш класс (должна быть причина, по которой он вставляет + отображение + откат, но чего не хватает в вашем объяснении?) лучше напишите еще один вопрос и сообщите все детали.
  • Второе решение («не рекомендуется, неэффективно и опасно»), если вы действительно хотите придерживаться своей текущей логики: переместите дисплей в функциональный модуль с поддержкой RFC и выполните CALL FUNCTION '...' DESTINATION 'NONE' KEEPING LOGICAL UNIT OF WORK (ср. документация ). Это не рекомендуется, потому что это только для внутреннего использования. Это неэффективно, потому что занимает 2 рабочих процесса одновременно. Это опасно, потому что «наихудшим сценарием может быть выключение системы ».
4 голосов
/ 30 марта 2019

Как избежать неявного принятия

Чтобы избежать неявной фиксации, вы можете обернуть INSERT в МОДУЛЬ ФУНКЦИЙ ОБНОВЛЕНИЯ . ФУНКЦИЯ ВЫЗОВА В ОБНОВЛЕНИИ ЗАДАЧА как SAP LUW, фактическая вставка произойдет только при вызове COMMIT WORK.

Цитата от вас:

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

Полагаю, ваша база данных поддерживает Committed Read

Совершенное чтение

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

Но в SAP LUW нельзя ожидать, что вы можете выбрать вставленную запись, которая вставляется в МОДУЛЬ ФУНКЦИИ UPDATE перед оператором COMMIT WORK.

Я предлагаю вам всегда работать с внутренней таблицей, чтобы выполнить вставку и отображение ALV, и предоставить кнопку SAVE, чтобы инициировать вставку из внутренних таблиц в таблицу базы данных.

...