SAP Career Guide - A beginner’s manual on SAP careers for students and professionals

Tolles Buch - ein komplexes Thema mit den wichtigsten Punkten kurz und knackig erläutert.

C. Zollmer

Schnittstellenprogrammierung in SAP ABAP

Dieses Buch bietet einen einfachen Einstieg in die Welt der ABAP-Schnittstellen. Es führt in alle relevanten klassischen Technologien für die System-zu-System-Kommunikation mit ABAP ein, einschließlich synchroner und asynchroner Techniken.Im Mittelpunkt s...

Leseprobe

Inhaltsverzeichnis

  • Einführung
  • Danksagung
  • 1 Remote Function Call (RFC) nutzen
  • 2 BAPIs nutzen
  • 3 IDocs und ALE
  • 4 SAP-Konnektoren
  • 5 RFM und BAPIs in SAP S/4HANA
  • A Über den Autor
  • B Disclaimer

Weitere Informationen

Autor/in:

Boris Rubarth

Katgorie:

SAP-Programming

Sprache:

Deutsch

Leseprobe

1.22 sRFC und bgRFC vergleichen

Lassen Sie uns nun eine RFC-Client-Anwendung erstellen, die unseren neuen RFM aufruft und im Ziel einen neuen Athleten anlegt.

Als ersten Schritt diskutieren und implementieren wir den sRFC. Danach werden wir den bgRFC implementieren, um ein exactly-once-Verhalten sicherzustellen.

1.22.1 sRFC implementieren

sRFC zum Anlegen eines Athleten nutzen

Die Client-Anwendung ähnelt unserer RFC-Anwendung zum Lesen von Daten, siehe Listing 1.17.

REPORT z_create_new_athlete_sync.
 
PARAMETERS: pa_name(23) LOWER CASE,
pa_bdate TYPE dats DEFAULT sy-datum,
pa_com(1) DEFAULT 'X',
pa_cntry TYPE land1,
pa_dest TYPE rfcdes-rfcdest DEFAULT 'FIRSTDEST'.
 
DATA: lv_id(12) TYPE n, gv_msg(100).
 
*Consistency checks
IF pa_name IS INITIAL OR
  pa_bdate IS INITIAL OR
  pa_cntry IS INITIAL.
  WRITE: 'Missing parameter'.
  EXIT.
ENDIF.
 
TRY.
  CALL METHOD cl_isu_date_check=>date_check_plausibility
    EXPORTING
      x_date                    = pa_bdate
    EXCEPTIONS
      plausibility_check_failed = 1
      OTHERS                    = 2.
  IF sy-subrc NE 0.
    WRITE: 'Invalid date'.
  ENDIF.
ENDTRY.
 
CALL FUNCTION 'Z_CREATE_ATHLETE'
  DESTINATION pa_dest
  EXPORTING
    i_athlete_name        = pa_name
    i_date_of_birth       = pa_bdate
    i_country             = pa_cntry
    i_do_commit           = pa_com
  IMPORTING
    e_athlete_id          = lv_id
  EXCEPTIONS
    missing_authorization = 1
    invalid_data          = 2
    object_locked         = 3
    system_failure        = 4  MESSAGE gv_msg
    communication_failure = 5  MESSAGE gv_msg
    OTHERS                = 6.
 
CASE sy-subrc.
  WHEN 0.
    WRITE: 'Call done, ', lv_id.
  WHEN 4 OR 5.
    WRITE: 'error:', gv_msg.
  WHEN OTHERS.
    WRITE: 'error: ', sy-subrc.
ENDCASE.

Listing 1.17: sRFC an einen RFM für eine Datenbankänderung

Es ist gute Praxis, eine Datenüberprüfung bereits in der Client-Anwendung vorzunehmen, da dies unnötige Aufrufe verhindert, die das Zielsystem ohnehin abweisen würde.

Als besondere Übung lassen Sie uns eine Client-Anwendung untersuchen, die zwei Athleten ans Zielsystem sendet. Die Annahme ist, dass beide zusammengehören, sodass wir nur beide oder keinen Athleten anlegen wollen. Wir bündeln beide Datensätze in einer LUW, indem wir erst nach dem zweiten Aufruf den I_DO_COMMIT-Parameter belegen. Listing 1.18 illustriert diesen Ansatz.

...
CALL FUNCTION 'Z_CREATE_ATHLETE'
DESTINATION pa_dest
  EXPORTING
    i_athlete_name              = 'First Athlete'
    i_date_of_birth             = pa_bdate1
    i_country                   = pa_cntry
    i_do_commit                 = ''
...
CALL FUNCTION 'Z_CREATE_ATHLETE'
DESTINATION pa_dest
  EXPORTING
    i_athlete_name              = 'Second Athlete'
    i_date_of_birth             = pa_bdate2
    i_country                   = pa_cntry
    i_do_commit                 = 'X'
...

Listing 1.18: Zwei sRFCs in einer LUW

Da für einen sRFC die Verbindung gehalten wird, werden beide Aufrufe in einer LUW ausgeführt und gemeinsam verbucht.

Können wir den I_DO_COMMIT-Parameter für den zweiten Aufruf auch weglassen und einfach die COMMIT WORK-Anweisung ausführen, so wie beim bgRFC? Natürlich nicht, da diese Anweisung nur lokal ausgeführt und nicht ins Zielsystem übertragen wird. Für den bgRFC wird die notwendige COMMIT WORK-Anweisung auch nicht ins Zielsystem übertragen, aber sie triggert die Ausführung der bgRFC Units.

Ermöglichen einer externen COMMIT WORK-Anweisung für einen sRFC

Als abschließenden Teil unserer sRFC-Diskussion lassen Sie uns nun annehmen, dass ein RFM eine externe COMMIT WORK-Anweisung benötigt, aber nicht den nützlichen Parameter I_DO_COMMIT bietet. Wir müssen daher die COMMIT WORK-Anweisung mit einem zweiten Aufruf über die bestehende RFC-Verbindung ans Ziel übersenden. Dafür machen wir uns wieder den RFM zu Nutze, der die COMMIT WORK-Anweisung beinhaltet: BAPI_TRANSACTION_COMMIT (natürlich nur dann, wenn der erste Aufruf erfolgreich war). Eine Vorlage für diesen Ansatz zeigt Listing 1.19.

...
CALL FUNCTION 'Z_CREATE_ATHLETE'
DESTINATION pa_dest
  EXPORTING
    i_athlete_name              = 'First Athlete'
    i_date_of_birth             = pa_bdate1
    i_country                   = pa_cntry
    i_do_commit                 = ''
...
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
DESTINATION pa_dest
...

Listing 1.19: Übermitteln einer externen COMMIT WORK-Anweisung

RFC-Verbindung erlaubt LUW

Erinnern Sie sich daran, dass die RFC-Verbindung nach der sRFC-Anweisung bestehen bleibt, solange der Kontext der Client-Anwendung existiert. Dadurch sind zwei aufeinanderfolgende Aufrufe in einer LUW möglich.

Wenn wir stattdessen zwei RFC-Aufrufe separieren wollen, damit sie nicht über die dieselbe Verbindung (und die dieselbe LUW) ausgeführt werden, dann muss die RFC-Verbindung geschlossen werden. Dies können wir nach dem ersten RFC-Aufruf über einen lokalen Aufruf an den Funktionsbaustein RFC_CONNECTION_CLOSE erreichen. Aber bedenken Sie, dass dies eine negative Auswirkung auf die Performance hat, da der zweite RFC-Aufruf die Verbindung wieder öffnen muss.

Was passiert nun, wenn die Verbindung für unseren sRFC-Client abbricht – wie wissen wir, ob die Daten bereits erfolgreich verbucht wurden? Dafür gibt es keinen einfachen Weg. Deshalb nutzen wir jetzt lieber den bgRFC, um eine exactly-once Verarbeitung sicherzustellen.

1.22.2 bgRFC zum Anlegen eines Athleten nutzen

Keine COMMIT WORK-Anweisung in einem RFM für asynchrone Verarbeitung

Ein RFM, der asynchron aufgerufen wird, darf selbst keine COMMIT WORK-Anweisung enthalten, da diese Anweisung automatisch durch die ABAP-Laufzeit des Zielsystems ausgeführt wird. Deshalb müssen wir beim bgRFC-Aufruf an unseren RFM den Parameter I_DO_COMMIT initial halten.

Listing 1.20 zeigt exemplarisch den bgRFC-Aufruf.

REPORT z_create_new_athlete_async.
 
PARAMETERS: pa_name(23) LOWER CASE,
pa_bdate TYPE dats DEFAULT sy-datum,
pa_cntry TYPE land1,
pa_dest TYPE rfcdes-rfcdest DEFAULT 'FIRSTDEST'.
data:
gv_dest TYPE ref TO if_bgrfc_destination_outbound,
go_trfc_unit TYPE ref TO if_trfc_unit_outbound,
ge_invalid_dest TYPE ref TO cx_bgrfc_invalid_destination.
 
DATA: lv_name TYPE c LENGTH 23.
 
*Consistency checks
  IF pa_name IS INITIAL OR
    pa_bdate IS INITIAL OR
    pa_cntry IS INITIAL.
    WRITE: 'Missing parameter'.
    EXIT.
  ENDIF.
 
TRY.
CALL METHOD cl_isu_date_check=>date_check_plausibility
   EXPORTING
     x_date                    = pa_bdate
   EXCEPTIONS
     plausibility_check_failed = 1
     others                   Abbildung = 2.
IF  sy-subrc ne 0.
  WRITE: 'Invalid date'.
  EXIT.
  ENDIF.
ENDTRY.
 
TRY.
gv_dest =
cl_bgrfc_destination_outbound=>create( pa_dest ).
go_trfc_unit = gv_dest->create_trfc_unit( ).
 
CALL FUNCTION 'Z_CREATE_ATHLETE'
  IN BACKGROUND UNIT go_trfc_unit
    EXPORTING
    i_athlete_name              = pa_name
    i_date_of_birth             = pa_bdate
    i_country                   = pa_cntry
    i_do_commit                 = ''
          .
 
  IF sy-subrc NE 0.
     WRITE: 'UNEXPECTED ERROR', sy-subrc.
     STOP.
   ENDIF.
      WRITE 'tRFC queue filled'.
 
CATCH cx_bgrfc_invalid_destination INTO ge_invalid_dest.
  WRITE ge_invalid_dest->get_text( ).
  EXIT.
ENDTRY.
 
COMMIT WORK.
WRITE 'Commit work done'.

Listing 1.20: Asynchrone RFC-Client-Anwendung mit bgRFC

Wir können also mit der Nutzung des bgRFC sicherstellen, dass ein Datensatz nur einmal verbucht wird, selbst im Fall eines Verbindungsabbruchs.

Aber wie sieht es mit ungültigen Daten aus, die nicht bereits in der Client-Anwendung entdeckt wurden? Es gibt keine Rückmeldung für Fehler aufgrund ungültiger Daten. Um sicherzustellen, dass wirklich nur gültige Daten gesendet werden, können Sie einen sRFC mit einem nachfolgenden bgRFC kombinieren. Der sRFC wird zunächst prüfen, ob die Daten im Zielsystem akzeptiert werden, wird aber nicht den Parameter I_DO_COMMIT setzen. Danach, wenn der erste Aufruf erfolgreich war, sendet der bgRFC die bereits validierten Daten, damit sie im Zielsystem verbucht werden. Da dies eine einfache Kombination unserer letzten beiden Listings ist, zeige ich in Listing 1.21 nur das Prinzip. Bedenken Sie, dass diese Kombination nicht so performant ist, als wenn Sie nur den bgRFC ausführten. Dafür werden ungültige Daten einfacher entdeckt.

...
* sRFC to check if data are accepted
CALL FUNCTION 'Z_CREATE_ATHLETE'
DESTINATION pa_dest
  EXPORTING
    i_athlete_name              = lv_name
    i_date_of_birth             = pa_bdate1
    i_country                   = pa_cntry
    i_do_commit                 = ''
 EXCEPTIONS
   missing_authorization       = 1
   invalid_data                = 2
   object_locked               = 3
   OTHERS                      = 4
          .
IF sy-subrc  0.
  WRITE: 'Data not accepted:', sy-subrc.
  EXIT.
ELSE.
...
* bgRFC for data creation 
 CALL FUNCTION 'Z_CREATE_ATHLETE'
   IN BACKGROUND UNIT go_trfc_unit
   EXPORTING
     i_athlete_name              = lv_name
     i_date_of_birth             = pa_bdate1
     i_country                   = pa_cntry
     i_do_commit                 = ''
...
 COMMIT WORK.
ENDIF.

Listing 1.21: sRFC-Datenprüfung vor einem bgRFC-Aufruf

Eine andere Frage: Wie legen Sie zwei Athleten in einer LUW an? Können Sie einfach den bgRFC-Aufruf kopieren und eine COMMIT WORK-Anweisung am Ende einfügen so wie zuvor für den sRFC? Ja, aber Sie müssen natürlich zunächst entscheiden, ob die beiden Athleten wirklich in dieselbe LUW gehören.

Wenn Sie beide Athleten in eine LUW packen wollen, dann nutzen Sie dieselbe Unit qo_unit für beide Aufrufe. Ansonsten legen Sie für jeden Aufruf eine eigene Unit an, wie in Listing 1.22 gezeigt:

gv_dest =
cl_bgrfc_destination_outbound=>create( pa_dest ).
go_unit = gv_dest->create_trfc_unit( ).
 
CALL FUNCTION 'Z_CREATE_ATHLETE'
  IN BACKGROUND UNIT go_unit
    EXPORTING
    i_athlete_name              = lv_name1
    i_date_of_birth             = pa_bdate
    i_country                   = pa_cntry
.
...
* This creates a separate unit for the second call
* and decouples the two athletes:
go_unit2 = gv_dest->create_trfc_unit( ).
 
CALL FUNCTION 'Z_CREATE_ATHLETE'
  IN BACKGROUND UNIT go_unit2
    EXPORTING
    i_athlete_name              = lv_name2
    i_date_of_birth             = pa_bdate
    i_country                   = pa_cntry
.
...
COMMIT WORK.

Listing 1.22: Zwei bgRFC-Aufrufe in gleicher oder separater LUW

Ist in diesem Fall wieder eine Queue notwendig, um die Reihenfolge festzulegen, in der die Athleten angelegt werden? (Dies erfordert einen bgRFC mit Units vom Typ qRFC.) Wenn beide Athleten zur selben LUW gehören, benötigen wir keine Queue, da die Reihenfolge innerhalb der LUW erhalten bleibt. Aber wenn Sie sich für zwei separate Units entscheiden, dann ist die Reihenfolge nicht sichergestellt, und Sie könnten überlegen, mittels einer Queue die Reihenfolge zu bestimmen. In unserem Beispiel – dem Anlegen von Athleten – ist das typischerweise nicht notwendig.

Alle Inhalte. Mehr Informationen. Jetzt entdecken.

et.training - Ihre Lernplattform für SAP-Software

  • Zugriff auf alle Lerninhalte1
  • Regelmäßige Neuerscheinungen
  • Intelligenter Suchalgorithmus
  • Innovatives Leseerlebnis
  • Maßgeschneidere Lernpfade
  • Zertifikate & QA-Tests2

Sie haben bereits ein Konto?

1 Sie erhalten Zugriff auf alle Lerninhalte. Online-Trainings, Zertifikate sind NICHT Teil der Flatrate.

2 Weitere Informationen auf Anfrage.