ABAP Cloud - Sperren
Für was musst du Sperren setzen und wie kannst du das leicht in ABAP Cloud machen? In diesem Artikel schauen wir uns den Prozess im Detail an.
Inhaltsverzeichnis
In diesem Artikel werden wir auf das Thema Sperren eingehen, wie du sie nutzt und für was du sie eigentlich brauchst. Dabei werden wir auf die Details mit ABAP Cloud eingehen.
Einleitung
Bereits in der Ausbildung sollte ein ABAP Entwickler lernen, dass man eine Tabelle oder einen Prozess sperrt, bevor er ändernde Aktionen durchführt. Die Sperre sorgt dafür, dass nur er den Datensatz ändern kann und keine parallelen Änderungen durchgeführt werden. Nur das stellt sicher, dass Änderungen sauber und sicher übernommen werden. Sperren werden vor allem dann gesetzt, wenn Datensätze geändert werden, können aber auch dann erfolgen, wenn ein User in einem Datensatz in den Änderungsmodus geht. Damit erhalten andere User eine Meldung, wenn sie versuchen in den Änderungsmodus zu gehen oder ändernde Operationen im System machen.
In einem klassischen System kannst du über die Transaktion SM12 deine eigenen Sperren und mit genügend Berechtigungen auch fremde Sperren im System sehen. Hast du administrative Berechtigungen, kannst du auch Sperreinträge aus dem System löschen, wenn Prozesse nicht sauber beendet wurden.
ENQ Prozess
Im System gibt es einen Prozesstype "ENQ", der für die Verwaltung der Sperren zuständig ist. Dieser setzt und entfernt sperren und prüft weitere Anfragen. Ist bereits eine Schreibsperre auf einem Datensatz gesetzt, werden weitere Anfragen von anderen Usern abgelehnt und es erfolgt eine entsprechende Benachrichtigung. Der Sperrprozess ist im System einmalig, auch wenn mehrere Applikationsserver aktiv sind, um das Setzen der Sperren konsistent zu halten.
Die Sperren werden in der Sperrtabelle verwaltet, was aber auch zu Fehlern in Prozessen führen kann. Wenn ein Prozess zum Beispiel 300.000 Sperren erzeugen würde und die Sperrtabelle damit voll wäre, können andere Prozesse im System keine Sperren mehr absetzen und es wären damit keine Änderungsoperationen mehr möglich.
Grundobjekte
Damit wir nun Sperren im System setzen können, benötigen wir erst einmal eine Haupttabelle zum Setzen der Sperre und ein Sperrobjekt im System.
Tabelle
Dazu definieren wir eine einfache Tabelle.
@EndUserText.label : 'Lock Entries'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zbs_dmo_lock {
key client : abap.clnt not null;
key identification : abap.int4 not null;
description : abap.char(120);
value_date : abap.dats;
}
Sperrobjekt
Im zweiten Schritt legen wir unser Sperrobjekt im System an. Dazu auf das System oder dein Paket Rechts-Klick ausführen und über das Menü "New -> Other ABAP Repository Object" wählen. Dort findest du ein entsprechendes Objekt, welches wir im nächsten Schritt anlegen wollen.
Sperrobjekte im Kundennamensraum müssen immer mit EY* oder EZ* beginnen, daher sieht die Benamung des Objektes erst einmal etwas gewöhnungsbedürftig aus. Ebenfalls hinterlegen wir unsere Tabelle als primäre Tabelle.
Mit "Next" und der Zuordnung zum Transport, können wir die Anlage des Objekts abschließen. Nun muss das Objekt noch aktiviert werden, damit die Sperrbausteine im System generiert werden. Vorher sollten wir aber noch einen "Lock Mode" definieren. Nach der Generierung sieht das Objekt wie folgt aus:
Hier findest du verschiedene Informationen und kannst weitere Einstellungen am Objekt vornehmen. Dazu einige Einstellungen beschrieben
- Lock Mode - Es können verschiedene Arten von Sperren gesetzt werden. Üblich ist die Schreibsperre, damit du Änderungen am Datensatz durchführen kannst.
- Allow RFC - Ist die Checkbox aktiv, sind die Funktionsbausteine RFC-fähig und können aus anderen Systemen aufgerufen werden.
- Secondary Tables - Hier können weitere Tabellen mit Fremdschlüsselbeziehung hinzugefügt werden, wenn es entsprechend Sinn ergibt.
Verwendung
Die Sperre wird üblicherweise dann gesetzt, wenn der User in den Änderungsmodus des Datensatzes geht oder kurz bevor die Änderung durchgeführt werden soll. Beim Setzen der Sperre erhältst du auch die Information, ob der Datensatz bereits gesperrt ist.
Generische Sperre
Setzen wir im ersten Beispiel eine generische Sperre. Dazu erzeugen wir über die Factory CL_ABAP_LOCK_OBJECT_FACTORY ein entsprechendes Objekt für unser Sperrobjekt.
DATA(lo_lock) = cl_abap_lock_object_factory=>get_instance( 'EZBS_DEMO_LOCK' ).
Im nächsten Schritt können wir dann die ENQUEUE Methode des neuen Objekts aufrufen und setzen damit eine Sperre im System. Da wir keine Parameter übergeben haben, wird eine allgemeine Sperre auf die ganze Tabelle gesetzt.
lo_lock->enqueue( ).
Das erzeugte Objekt ist vom Typ IF_ABAP_LOCK_OBJECT.
Datensatz sperren
Wollen wir nun einen spezifischen Datensatz sperren, erzeugen wir uns über die Factory wieder ein spezifisches Objekt für unser Sperrobjekt. Dann befüllen wir den Übergabeparameter IT_PARAMETER und übergeben die Sperrargumente. In diesem Fall wollen wir den Datensatz mit der Identifikation 12 sperren.
lo_lock->enqueue( it_parameter = VALUE #( ( name = 'IDENTIFICATION' value = REF #( 12 ) ) ) ).
Das Client Feld ist ebenfalls im Schlüssel enthalten, muss allerdings nicht zwingend befüllt werden. Ist der Parameter nicht gesetzt, wird vom System die Vorbelegung durchgeführt.
Sperre prüfen
Um nun das Sperrverhalten zu testen, legen wir im Grunde eine ausführbare Klasse an, die die Logik für uns implementiert. So eine Klasse könnte also wie folgt aussehen.
CLASS zcl_bs_demo_locks DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
ENDCLASS.
CLASS zcl_bs_demo_locks IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
TRY.
DATA(lo_lock) = cl_abap_lock_object_factory=>get_instance( 'EZBS_DEMO_LOCK' ).
lo_lock->enqueue( it_parameter = VALUE #( ( name = 'IDENTIFICATION' value = REF #( 13 ) ) ) ).
CATCH cx_abap_foreign_lock INTO DATA(lo_locked).
out->write( |Locked by { lo_locked->user_name }| ).
CATCH cx_abap_lock_failure.
out->write( `Failed ...` ).
ENDTRY.
ENDMETHOD.
ENDCLASS.
Im nächsten Schritt starten wir die Klasse per F9 in den ABAP Development Tools (Eclipse) und halten per Debugging beim Setzen der Sperre. Wenn wir die Enqueue Methode ausgeführt haben, können wir die Klasse noch einmal starten und sollten nun einen Fehler erhalten. Die erste Instanz müssen wir dazu aber immer noch im Debugger halten, da sonst die Sperre wieder aufgelöst wird, wenn die Klasse durchlaufen wurde. Es können zwei Ausnahme erzeugt werden, wenn wir versuchen die Sperre zu setzen:
- CX_ABAP_FOREIGN_LOCK - Wird ausgelöst, wenn bereits eine Sperre auf dem gleichen Datensatz liegt. Über das Attribut USER_NAME kommst du an die User-ID des sperrenden Users, wenn du eine Fehlermeldung ausgeben möchtest.
- CX_ABAP_LOCK_FAILURE - Hierbei handelt es sich um eine generische Fehlermeldung, wenn es Probleme mit dem Customizing des Sperrobjekts oder den übergebenen Parametern gibt. Weitere Informationen kannst du dann der Meldung oder weiteren Parametern im Objekt entnehmen.
Anzeige
On-Premise kannst du dir mit den nötigen Berechtigungen in der Transaktion SM12 oder SMENQ deine und andere Sperren anschauen, die aktuell im System bestehen. In ABAP Cloud kannst du dir die Sperren erst einmal wie gewohnt in den Transaktionen anschauen. In der BTP steht zusätzlich auch die App "Maintain User Sessions" (F6049) zur Verfügung, die aber nicht den vollen Umfang der Transaktion abdeckt. Mit der App siehst du User, die Sperren im System gesetzt haben und halten und kannst diese Prozesse über die App auch löschen.
Fazit
Für den Aufruf der generischen Funktionsbausteine hat SAP nun eine leichter zugängliche Klasse zur Verfügung gestellt, die eine einfachere Schnittstelle zur Verfügung stellt. Im Hintergrund hat sich allerdings nicht so viel geändert und vieles wird dir gewohnt vorkommen.
Weitere Informationen:
SAP Community Q&A
SAP Help - Enqueue Server