ABAP Lock Objects: ENQUEUE, DEQUEUE, Lock Management

Category
ABAP-Statements
Published
Author
Johannes

Lock Objects ensure data consistency when multiple users access data simultaneously. Locks are set and released with ENQUEUE and DEQUEUE.

Basic Concept

TermDescription
Lock ObjectDefinition in SE11, generates ENQUEUE/DEQUEUE FMs
ENQUEUESet lock
DEQUEUERelease lock
Exclusive Lock (E)Exclusive write access
Shared Lock (S)Shared read access
Optimistic Lock (O)Optimistic, only lock on change

Lock Modes

ModeDescriptionCompatible with
E (Exclusive)Write lockNone
S (Shared)Read lockS
X (Exclusive, non-cumulative)Strict write lockNone
O (Optimistic)OptimisticS, 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_CUSTOMER

2. Simple Lock Set and Release

DATA: lv_kunnr TYPE kunnr VALUE '0000001000'.
" Set lock
CALL 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.
" Usage
DATA(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 seconds
CALL 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 timeout
DATA: 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 immediately
DATA: lt_customers TYPE TABLE OF kunnr.
lt_customers = VALUE #( ( '0000001000' ) ( '0000001001' ) ( '0000001002' ) ).
" Collect locks
LOOP 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 once
CALL 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 back
ENDIF.

6. Shared Lock for Read Access

" Shared Lock - multiple readers possible simultaneously
CALL 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 KNA1
CALL 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 program
CALL FUNCTION 'DEQUEUE_ALL'.
" Alternatively: Specific lock object
CALL FUNCTION 'DEQUEUE_EZ_CUSTOMER'
EXPORTING
mode_kna1 = 'E'
kunnr = space. " Empty = All locks of this object

10. 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 items
CALL 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 task
CALL FUNCTION 'Z_UPDATE_CUSTOMER' IN UPDATE TASK
EXPORTING
is_customer = ls_customer.
COMMIT WORK.
" Lock is automatically released after update task

12. 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 lock
CLASS 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.
" Report
WRITE: / '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-CLEANUP
TRY.
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

  1. SE11 → Lock Object → Name: EZ_<Name>
  2. Specify primary table
  3. Define lock arguments (key fields)
  4. 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.