Lock Objects ensure data consistency when multiple users access data simultaneously. Locks are set and released with ENQUEUE and DEQUEUE.
Basic Concept
| Term | Description |
|---|---|
| Lock Object | Definition in SE11, generates ENQUEUE/DEQUEUE FMs |
| ENQUEUE | Set lock |
| DEQUEUE | Release lock |
| Exclusive Lock (E) | Exclusive write access |
| Shared Lock (S) | Shared read access |
| Optimistic Lock (O) | Optimistic, only lock on change |
Lock Modes
| Mode | Description | Compatible with |
|---|---|---|
| E (Exclusive) | Write lock | None |
| S (Shared) | Read lock | S |
| X (Exclusive, non-cumulative) | Strict write lock | None |
| O (Optimistic) | Optimistic | S, O |
Examples
1. Create Lock Object (SE11)
Lock Object: EZ_CUSTOMER
Tables:- KNA1 (Primary Table)
Lock Arguments:- MANDT (from KNA1)- KUNNR (from KNA1)
Generated Function Modules:- ENQUEUE_EZ_CUSTOMER- DEQUEUE_EZ_CUSTOMER2. Simple Lock Set and Release
DATA: lv_kunnr TYPE kunnr VALUE '0000001000'.
" Set lockCALL FUNCTION 'ENQUEUE_EZ_CUSTOMER' EXPORTING mode_kna1 = 'E' " Exclusive Lock mandt = sy-mandt kunnr = lv_kunnr EXCEPTIONS foreign_lock = 1 " Already locked by another system_failure = 2 OTHERS = 3.
IF sy-subrc = 0. " Lock successful - edit data UPDATE kna1 SET name1 = 'New Name' WHERE kunnr = lv_kunnr.
COMMIT WORK.
" Release lock CALL FUNCTION 'DEQUEUE_EZ_CUSTOMER' EXPORTING mode_kna1 = 'E' mandt = sy-mandt kunnr = lv_kunnr.
ELSEIF sy-subrc = 1. " Locked by another user MESSAGE |Customer { lv_kunnr } is locked by { sy-msgv1 }| TYPE 'E'.ENDIF.3. Lock Class for Clean Handling
CLASS zcl_customer_lock DEFINITION. PUBLIC SECTION. METHODS: lock IMPORTING iv_kunnr TYPE kunnr RETURNING VALUE(rv_success) TYPE abap_bool.
METHODS: unlock IMPORTING iv_kunnr TYPE kunnr.
METHODS: unlock_all.
METHODS: is_locked IMPORTING iv_kunnr TYPE kunnr RETURNING VALUE(rv_locked) TYPE abap_bool.
METHODS: get_lock_owner IMPORTING iv_kunnr TYPE kunnr RETURNING VALUE(rv_user) TYPE sy-uname.
PRIVATE SECTION. DATA: mt_locked_customers TYPE TABLE OF kunnr.ENDCLASS.
CLASS zcl_customer_lock IMPLEMENTATION. METHOD lock. CALL FUNCTION 'ENQUEUE_EZ_CUSTOMER' EXPORTING mode_kna1 = 'E' mandt = sy-mandt kunnr = iv_kunnr _wait = abap_true " Wait if locked _collect = abap_false EXCEPTIONS foreign_lock = 1 system_failure = 2 OTHERS = 3.
IF sy-subrc = 0. rv_success = abap_true. APPEND iv_kunnr TO mt_locked_customers. ELSE. rv_success = abap_false. ENDIF. ENDMETHOD.
METHOD unlock. CALL FUNCTION 'DEQUEUE_EZ_CUSTOMER' EXPORTING mode_kna1 = 'E' mandt = sy-mandt kunnr = iv_kunnr.
DELETE mt_locked_customers WHERE table_line = iv_kunnr. ENDMETHOD.
METHOD unlock_all. LOOP AT mt_locked_customers INTO DATA(lv_kunnr). unlock( lv_kunnr ). ENDLOOP. ENDMETHOD.
METHOD is_locked. CALL FUNCTION 'ENQUEUE_EZ_CUSTOMER' EXPORTING mode_kna1 = 'E' mandt = sy-mandt kunnr = iv_kunnr _wait = abap_false EXCEPTIONS foreign_lock = 1 system_failure = 2 OTHERS = 3.
IF sy-subrc = 1. rv_locked = abap_true. ELSE. " Release lock again (was only a test) CALL FUNCTION 'DEQUEUE_EZ_CUSTOMER' EXPORTING mode_kna1 = 'E' mandt = sy-mandt kunnr = iv_kunnr. rv_locked = abap_false. ENDIF. ENDMETHOD.
METHOD get_lock_owner. DATA: lt_locks TYPE TABLE OF seqg3.
" Read all locks CALL FUNCTION 'ENQUEUE_READ' EXPORTING gname = 'KNA1' garg = |{ sy-mandt }{ iv_kunnr }| TABLES enq = lt_locks EXCEPTIONS communication_failure = 1 system_failure = 2 OTHERS = 3.
IF sy-subrc = 0 AND lt_locks IS NOT INITIAL. rv_user = lt_locks[ 1 ]-guname. ENDIF. ENDMETHOD.ENDCLASS.
" UsageDATA(lo_lock) = NEW zcl_customer_lock( ).
IF lo_lock->lock( '0000001000' ). " Processing...
lo_lock->unlock( '0000001000' ).ELSE. DATA(lv_owner) = lo_lock->get_lock_owner( '0000001000' ). MESSAGE |Locked by { lv_owner }| TYPE 'E'.ENDIF.4. Waiting for Lock
" With _WAIT = abap_true the call waits up to 10 secondsCALL FUNCTION 'ENQUEUE_EZ_CUSTOMER' EXPORTING mode_kna1 = 'E' kunnr = lv_kunnr _wait = abap_true " Enable waiting EXCEPTIONS foreign_lock = 1 system_failure = 2 OTHERS = 3.
" Or: Custom wait loop with timeoutDATA: lv_attempts TYPE i VALUE 0, lv_max_attempts TYPE i VALUE 10.
WHILE lv_attempts < lv_max_attempts. CALL FUNCTION 'ENQUEUE_EZ_CUSTOMER' EXPORTING kunnr = lv_kunnr _wait = abap_false EXCEPTIONS foreign_lock = 1 OTHERS = 2.
IF sy-subrc = 0. EXIT. " Lock obtained ENDIF.
lv_attempts = lv_attempts + 1. WAIT UP TO 1 SECONDS.ENDWHILE.
IF sy-subrc <> 0. MESSAGE 'Could not obtain lock' TYPE 'E'.ENDIF.5. Collective Locks (_COLLECT)
" Collect locks instead of setting immediatelyDATA: lt_customers TYPE TABLE OF kunnr.
lt_customers = VALUE #( ( '0000001000' ) ( '0000001001' ) ( '0000001002' ) ).
" Collect locksLOOP AT lt_customers INTO DATA(lv_kunnr). CALL FUNCTION 'ENQUEUE_EZ_CUSTOMER' EXPORTING kunnr = lv_kunnr _collect = abap_true " Collect EXCEPTIONS foreign_lock = 1 OTHERS = 2.
IF sy-subrc <> 0. " Error handling ENDIF.ENDLOOP.
" Set all collected locks at onceCALL FUNCTION 'FLUSH_ENQUEUE' EXCEPTIONS foreign_lock = 1 system_failure = 2 OTHERS = 3.
IF sy-subrc <> 0. " At least one lock could not be set " All already set locks are rolled backENDIF.6. Shared Lock for Read Access
" Shared Lock - multiple readers possible simultaneouslyCALL FUNCTION 'ENQUEUE_EZ_CUSTOMER' EXPORTING mode_kna1 = 'S' " Shared Lock kunnr = lv_kunnr EXCEPTIONS foreign_lock = 1 system_failure = 2 OTHERS = 3.
IF sy-subrc = 0. " Read (others can also read) SELECT SINGLE * FROM kna1 WHERE kunnr = @lv_kunnr INTO @DATA(ls_customer).
CALL FUNCTION 'DEQUEUE_EZ_CUSTOMER' EXPORTING mode_kna1 = 'S' kunnr = lv_kunnr.ENDIF.7. Optimistic Locking
CLASS zcl_optimistic_lock DEFINITION. PUBLIC SECTION. METHODS: read_for_update IMPORTING iv_kunnr TYPE kunnr EXPORTING es_customer TYPE kna1 ev_timestamp TYPE timestampl.
METHODS: save_changes IMPORTING is_customer TYPE kna1 iv_timestamp TYPE timestampl RETURNING VALUE(rv_success) TYPE abap_bool.ENDCLASS.
CLASS zcl_optimistic_lock IMPLEMENTATION. METHOD read_for_update. " Set optimistic lock CALL FUNCTION 'ENQUEUE_EZ_CUSTOMER' EXPORTING mode_kna1 = 'O' " Optimistic kunnr = iv_kunnr EXCEPTIONS OTHERS = 1.
" Read data SELECT SINGLE * FROM kna1 WHERE kunnr = @iv_kunnr INTO @es_customer.
GET TIME STAMP FIELD ev_timestamp. ENDMETHOD.
METHOD save_changes. " Before saving: Try exclusive lock CALL FUNCTION 'ENQUEUE_EZ_CUSTOMER' EXPORTING mode_kna1 = 'E' kunnr = is_customer-kunnr _convert = abap_true " Convert O -> E EXCEPTIONS foreign_lock = 1 OTHERS = 2.
IF sy-subrc = 0. " Check if data was changed SELECT SINGLE aedat aezet FROM kna1 WHERE kunnr = @is_customer-kunnr INTO @DATA(ls_check).
" If changed in meantime -> Conflict " (Simplified check)
UPDATE kna1 FROM @is_customer. rv_success = xsdbool( sy-subrc = 0 ).
CALL FUNCTION 'DEQUEUE_EZ_CUSTOMER' EXPORTING mode_kna1 = 'E' kunnr = is_customer-kunnr. ELSE. rv_success = abap_false. ENDIF. ENDMETHOD.ENDCLASS.8. Read All Locks of an Object Type
DATA: lt_locks TYPE TABLE OF seqg3.
" Read all locks for table KNA1CALL FUNCTION 'ENQUEUE_READ' EXPORTING gclient = sy-mandt gname = 'KNA1' " Table name guname = '*' " All users TABLES enq = lt_locks EXCEPTIONS communication_failure = 1 system_failure = 2 OTHERS = 3.
IF sy-subrc = 0. LOOP AT lt_locks INTO DATA(ls_lock). WRITE: / 'Object:', ls_lock-garg, / 'User:', ls_lock-guname, / 'Mode:', ls_lock-gmode. ENDLOOP.ENDIF.9. DEQUEUE_ALL - Release All Own Locks
" Release all locks set by current programCALL FUNCTION 'DEQUEUE_ALL'.
" Alternatively: Specific lock objectCALL FUNCTION 'DEQUEUE_EZ_CUSTOMER' EXPORTING mode_kna1 = 'E' kunnr = space. " Empty = All locks of this object10. Lock Object with Multiple Tables
Lock Object: EZ_ORDER (SE11)
Tables:- VBAK (Primary Table - Header)- VBAP (Secondary Table - Items)
Lock Arguments:- MANDT- VBELN (Common key)" One lock locks header and itemsCALL FUNCTION 'ENQUEUE_EZ_ORDER' EXPORTING mode_vbak = 'E' mode_vbap = 'E' vbeln = lv_vbeln EXCEPTIONS foreign_lock = 1 OTHERS = 2.
IF sy-subrc = 0. " Edit header and items UPDATE vbak SET ... WHERE vbeln = lv_vbeln. UPDATE vbap SET ... WHERE vbeln = lv_vbeln.
COMMIT WORK.
CALL FUNCTION 'DEQUEUE_EZ_ORDER' EXPORTING mode_vbak = 'E' mode_vbap = 'E' vbeln = lv_vbeln.ENDIF.11. Lock with Scope
" _SCOPE parameter determines lifetime" 1 = Dialog (default) - Lock released at COMMIT" 2 = Update Task - Lock passed to update task" 3 = Both
CALL FUNCTION 'ENQUEUE_EZ_CUSTOMER' EXPORTING mode_kna1 = 'E' kunnr = lv_kunnr _scope = '2' " For update task EXCEPTIONS OTHERS = 1.
" Change in update taskCALL FUNCTION 'Z_UPDATE_CUSTOMER' IN UPDATE TASK EXPORTING is_customer = ls_customer.
COMMIT WORK." Lock is automatically released after update task12. Deadlock Avoidance
CLASS zcl_deadlock_safe DEFINITION. PUBLIC SECTION. METHODS: lock_multiple IMPORTING it_keys TYPE ty_key_tab RETURNING VALUE(rv_success) TYPE abap_bool.
PRIVATE SECTION. METHODS: sort_keys CHANGING ct_keys TYPE ty_key_tab.ENDCLASS.
CLASS zcl_deadlock_safe IMPLEMENTATION. METHOD lock_multiple. DATA: lt_keys TYPE ty_key_tab.
lt_keys = it_keys.
" IMPORTANT: Always lock in same order " prevents deadlocks sort_keys( CHANGING ct_keys = lt_keys ).
" Set locks LOOP AT lt_keys INTO DATA(ls_key). CALL FUNCTION 'ENQUEUE_EZ_CUSTOMER' EXPORTING kunnr = ls_key-kunnr _wait = abap_false EXCEPTIONS foreign_lock = 1 OTHERS = 2.
IF sy-subrc <> 0. " Rollback: Release already set locks DATA(lv_index) = sy-tabix - 1. LOOP AT lt_keys INTO DATA(ls_unlock) TO lv_index. CALL FUNCTION 'DEQUEUE_EZ_CUSTOMER' EXPORTING kunnr = ls_unlock-kunnr. ENDLOOP.
rv_success = abap_false. RETURN. ENDIF. ENDLOOP.
rv_success = abap_true. ENDMETHOD.
METHOD sort_keys. SORT ct_keys BY kunnr. ENDMETHOD.ENDCLASS.13. RAP: ETag and Optimistic Concurrency
" In RAP, concurrency is controlled via ETags" Behavior Definition:define behavior for ZI_Customer with etag master last_changed_at lock master{ update; delete;}
" Implementation for custom lockCLASS lhc_customer DEFINITION INHERITING FROM cl_abap_behavior_handler. PRIVATE SECTION. METHODS lock FOR LOCK IMPORTING keys FOR LOCK Customer.ENDCLASS.
CLASS lhc_customer IMPLEMENTATION. METHOD lock. LOOP AT keys INTO DATA(ls_key). CALL FUNCTION 'ENQUEUE_EZ_CUSTOMER' EXPORTING kunnr = ls_key-kunnr EXCEPTIONS foreign_lock = 1 OTHERS = 2.
IF sy-subrc <> 0. APPEND VALUE #( %tky = ls_key-%tky ) TO failed-customer.
APPEND VALUE #( %tky = ls_key-%tky %msg = NEW zcm_customer( severity = if_abap_behv_message=>severity-error textid = zcm_customer=>locked ) ) TO reported-customer. ENDIF. ENDLOOP. ENDMETHOD.ENDCLASS.14. Transaction SM12 - Display Lock Entries
" Programmatically display locks (like SM12)DATA: lt_locks TYPE TABLE OF seqg3.
CALL FUNCTION 'ENQUEUE_READ' EXPORTING guname = sy-uname " Only own locks TABLES enq = lt_locks EXCEPTIONS OTHERS = 1.
" ReportWRITE: / 'Active locks:'.WRITE: / '---------------'.
LOOP AT lt_locks INTO DATA(ls_lock). WRITE: / 'Table:', ls_lock-gname, / 'Argument:', ls_lock-garg, / 'Mode:', ls_lock-gmode, / 'User:', ls_lock-guname, / 'Time:', ls_lock-gttime. SKIP.ENDLOOP.15. Cleanup on Program Abort
CLASS zcl_lock_manager DEFINITION. PUBLIC SECTION. METHODS: constructor. METHODS: destructor. " Called on garbage collection
METHODS: lock_customer IMPORTING iv_kunnr TYPE kunnr.
PRIVATE SECTION. DATA: mt_locks TYPE TABLE OF kunnr.ENDCLASS.
CLASS zcl_lock_manager IMPLEMENTATION. METHOD constructor. " Optional: Register for cleanup ENDMETHOD.
METHOD destructor. " Release locks when object is destroyed LOOP AT mt_locks INTO DATA(lv_kunnr). CALL FUNCTION 'DEQUEUE_EZ_CUSTOMER' EXPORTING kunnr = lv_kunnr. ENDLOOP. ENDMETHOD.
METHOD lock_customer. CALL FUNCTION 'ENQUEUE_EZ_CUSTOMER' EXPORTING kunnr = iv_kunnr EXCEPTIONS OTHERS = 1.
IF sy-subrc = 0. APPEND iv_kunnr TO mt_locks. ENDIF. ENDMETHOD.ENDCLASS.
" Usage with TRY-CLEANUPTRY. DATA(lo_lock) = NEW zcl_lock_manager( ). lo_lock->lock_customer( '1000' ).
" Processing...
CLEANUP. " Executed also on exceptions IF lo_lock IS BOUND. CLEAR lo_lock. " Triggers destructor ENDIF.ENDTRY.Create Lock Object in SE11
- SE11 → Lock Object → Name:
EZ_<Name> - Specify primary table
- Define lock arguments (key fields)
- Activate → generates ENQUEUE/DEQUEUE FMs
Important Notes / Best Practice
- Always call DEQUEUE – even in error cases.
- Keep locks short – only during changes.
- Same order for multiple locks (deadlock avoidance).
- _WAIT = abap_true for automatic waiting.
- _COLLECT for atomic setting of multiple locks.
- Optimistic Locking for long processing times.
- SM12 for analyzing active locks.
- COMMIT WORK releases locks (Scope 1).
- Name Lock Objects with EZ_ naming convention.
- Combine with Exception Classes for error handling.