Skip to content

Commit 0f0de0d

Browse files
authored
Enhance locks.md with detailed locking strategies
Expanded the guide on locking business objects in abap2UI5 apps, detailing various locking strategies and scenarios with examples.
1 parent fccc744 commit 0f0de0d

1 file changed

Lines changed: 215 additions & 31 deletions

File tree

docs/development/specific/locks.md

Lines changed: 215 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,220 @@
1-
---
2-
outline: [2, 4]
3-
---
4-
# Locks
5-
6-
Business logic often needs to prevent two users from editing the same object at the same time. Because abap2UI5 runs stateless by default, locks held with `ENQUEUE` / `DEQUEUE` are released at the end of each roundtrip — so locking needs a deliberate approach.
7-
8-
### Lock with a Stateful Session
9-
Switch the session to stateful and call the lock function module. The lock survives subsequent roundtrips as long as the session stays stateful:
10-
```abap
11-
CALL FUNCTION `ENQUEUE_E_TABLE`
12-
EXPORTING
13-
tabname = `ZTEST`
14-
varkey = varkey
15-
EXCEPTIONS
16-
foreign_lock = 1
17-
system_failure = 2
18-
OTHERS = 3.
19-
20-
IF sy-subrc = 0.
21-
client->set_session_stateful( ).
22-
ELSE.
23-
client->set_session_stateful( abap_false ).
24-
ENDIF.
1+
# Locking Sales Orders in abap2UI5 — A Beginner's Guide
2+
3+
This guide explains **how to lock business objects in abap2UI5 apps**, step by step, starting from the simplest case and adding one layer at a time.
4+
5+
Every section points at a **complete, copy-paste-ready demo class** stored in this repository. To try a snippet:
6+
7+
1. Open the linked file.
8+
2. Create a new ABAP class with the matching name (e.g. `z2ui5_test_lock_01`).
9+
3. Paste the file contents as the class source.
10+
4. Activate it.
11+
5. Launch via the abap2UI5 launchpad URL with `?app=<class_name>`.
12+
13+
We use the **sales order header table `VBAK`** as the example throughout, because it ships with every SAP system and has a real, standard SAP enqueue object (`EVVBAK`).
14+
15+
## Repository layout
16+
17+
```
18+
scenarios/
19+
z2ui5_test_lock_01.clas.abap Scenario 1 — Naive editing (no locking)
20+
z2ui5_test_lock_02.clas.abap Scenario 2 — Enqueue at save
21+
z2ui5_test_lock_03.clas.abap Scenario 3 — Optimistic locking
22+
z2ui5_test_lock_04.clas.abap Scenario 4 — Enqueue + Optimistic (recommended)
23+
z2ui5_test_lock_05.clas.abap Scenario 5 — Stateful session
24+
z2ui5_test_lock_06.clas.abap Scenario 6 — Soft lock (advisory)
25+
z2ui5_test_lock_07.clas.abap Scenario 7 — Standard SAP BO draft via EML
26+
z2ui5_test_lock_08.clas.abap Scenario 8 — Platform lock manager (demo)
27+
28+
platform-lock-manager/
29+
README.md DDIC setup + function module interface
30+
z_request_locking.fugr.abap Reusable lock-handling function module
2531
```
2632

27-
Release the lock by ending the stateful session — for example on navigation away from the edit view:
28-
```abap
29-
client->set_session_stateful( abap_false ).
30-
client->nav_app_leave( ).
33+
---
34+
35+
## 1. Why is locking on the web different?
36+
37+
In classic SAP GUI, you open transaction `VA02`, the system calls `ENQUEUE_EVVBAK`, and **the lock lives as long as your dialog session lives**. You can think for ten minutes — the lock is still there.
38+
39+
A web app is **stateless** by default. Every roundtrip (HTTP POST) is a fresh ABAP session. A lock set during one roundtrip is gone by the next one. abap2UI5 lets you opt into **stateful sessions**, but you have to think about *when* you want that.
40+
41+
That difference creates the entire field of "web locking strategies." We will go through them one by one.
42+
43+
### The two questions you must answer
44+
45+
| Axis | Question |
46+
|---|---|
47+
| **A — Edit phase** | What happens while the user is *thinking and typing*? |
48+
| **B — Save phase** | What happens *the moment they hit save*? |
49+
50+
Every realistic app picks one strategy per axis. They compose.
51+
52+
---
53+
54+
## 2. Scenario 1 — Naive editing (no locking)
55+
56+
**Source:** [`scenarios/z2ui5_test_lock_01.clas.abap`](scenarios/z2ui5_test_lock_01.clas.abap)
57+
58+
The simplest possible starting point. The user can change a sales order and save. **There is no lock and no conflict check.** Last save wins, silently.
59+
60+
This is rarely what you want in production, but it is the right place to *start* — every later scenario layers a single concept on top of this one, so you can see exactly what each layer buys you.
61+
62+
**When to use this:**
63+
- Personal sandboxes, throwaway demos, internal tools where only one user ever touches a record
64+
65+
**Key idea:** `client->_bind_edit( auart )` creates a two-way binding — what the user types lands back in `auart` before the SAVE event fires. There is no lock and no check. If two users edit the same order, the second save silently wipes the first one's changes. Every later scenario fixes a specific piece of this problem.
66+
67+
---
68+
69+
## 3. Scenario 2 — Edit + Enqueue at save
70+
71+
**Source:** [`scenarios/z2ui5_test_lock_02.clas.abap`](scenarios/z2ui5_test_lock_02.clas.abap)
72+
73+
Now the user can change the sales order type. We do **not** hold a lock while they think. At the moment they press *Save*, we lock, write, commit, and release in one short roundtrip.
74+
75+
**When to use this:**
76+
- Quick edits with low chance of two users hitting the same record
77+
- Default starting point for most stateless editing apps
78+
79+
**Key idea:** the lock only exists for milliseconds, during the save event. Two users editing the same order in parallel will both succeed if neither saves at the literal same instant — the last save wins. That is a problem we fix in the next scenario.
80+
81+
---
82+
83+
## 4. Scenario 3 — Optimistic locking (timestamp check)
84+
85+
**Source:** [`scenarios/z2ui5_test_lock_03.clas.abap`](scenarios/z2ui5_test_lock_03.clas.abap)
86+
87+
Now we add a *conflict check*. On read we remember the record's last-changed timestamp. On save, we re-read it and **reject** if it changed in the meantime. This is the same idea as HTTP ETag or OData's `@odata.etag`.
88+
89+
**When to use this:**
90+
- Any time silent overwrites would be a problem
91+
- Combine with Scenario 2 — it costs almost nothing and catches real bugs
92+
93+
**Key idea:** `token_aedat`/`token_aezet` travel with the app session. On save, we re-read the live values from the database and reject if they have shifted. No lock is held during the edit phase, so this scales to many concurrent users.
94+
95+
---
96+
97+
## 5. Scenario 4 — Combined (the recommended default)
98+
99+
**Source:** [`scenarios/z2ui5_test_lock_04.clas.abap`](scenarios/z2ui5_test_lock_04.clas.abap)
100+
101+
Enqueue at save **and** the optimistic check. This is the safest stateless pattern and the one most production apps should default to.
102+
103+
**Why both:**
104+
- The enqueue serializes concurrent writers so two saves cannot interleave.
105+
- The timestamp check catches anyone who slipped in via another path (SE16, batch job, classic SAP GUI) between your read and your write.
106+
107+
**Key idea:** belt-and-suspenders. The enqueue prevents two parallel saves of *this* app from colliding. The timestamp check catches everything else.
108+
109+
---
110+
111+
## 6. Scenario 5 — Stateful session with a persistent enqueue
112+
113+
**Source:** [`scenarios/z2ui5_test_lock_05.clas.abap`](scenarios/z2ui5_test_lock_05.clas.abap)
114+
115+
Sometimes you want classic SAP GUI behaviour: the moment the user opens the screen, the lock is held until they save or leave. With `client->set_session_stateful( )`, abap2UI5 keeps the session alive between roundtrips so a real `ENQUEUE_EVVBAK` survives.
116+
117+
**When to use this:**
118+
- Internal back-office apps with few concurrent users
119+
- You want users to *immediately* see "locked by X" when opening
120+
121+
**Cost:** each active user pins a work process. Do **not** use this for high-traffic apps.
122+
123+
**Key idea:** while the app is open, an SM12 entry for `EVVBAK` / `0000004711` is visible. The user can navigate, type, wait — the lock stays. If they close the browser without pressing *Cancel*, the lock will eventually expire when the session times out.
124+
125+
**Compare with `z2ui5_cl_demo_app_350`** in the abap2UI5 demos repo for a similar pattern using `ENQUEUE_E_TABLE`.
126+
127+
---
128+
129+
## 7. Scenario 6 — Soft lock (advisory only)
130+
131+
**Source:** [`scenarios/z2ui5_test_lock_06.clas.abap`](scenarios/z2ui5_test_lock_06.clas.abap)
132+
133+
A soft lock is a row in a **custom Z table** marking *"user X is editing sales order Y."* It is **not** enforced by the SAP kernel — only your app code respects it. Use it for **UX feedback** ("locked by Alice since 09:32"), always layered on top of a real save-time guard.
134+
135+
### 7.1 Create the Z table
136+
137+
Create a small table in SE11 called `ZS_SO_LOCK`:
138+
139+
| Field | Type | Description |
140+
|------------|-------------|-----------------------|
141+
| MANDT | MANDT | Client (key) |
142+
| VBELN | VBELN_VA | Sales order (key) |
143+
| USERNAME | SYUNAME | Editing user |
144+
| LOCKED_AT | TIMESTAMPL | When the lock started |
145+
146+
Delivery class `A`. Activate.
147+
148+
### 7.2 The app
149+
150+
See [`scenarios/z2ui5_test_lock_06.clas.abap`](scenarios/z2ui5_test_lock_06.clas.abap).
151+
152+
**Key idea:** the soft lock decides *who can edit in the UI*. The enqueue + timestamp check decides *whether the save is allowed*. They serve different jobs.
153+
154+
**Gotcha:** if a user closes the browser without pressing *Release & Exit*, the row stays in `ZS_SO_LOCK` forever. In production you would add a small background job that deletes rows older than, say, 30 minutes.
155+
156+
---
157+
158+
159+
## 10. Side-by-side comparison
160+
161+
| Scenario | SM12 entry during edit | Pins WP | Survives browser close | Conflict detection | Complexity |
162+
|---|---|---|---|---|---|
163+
| 1 Naive editing ||||| trivial |
164+
| 2 Enqueue at save | only at save | no || at save (race possible) | low |
165+
| 3 Optimistic || no || at save (reliable) | low |
166+
| 4 **Enqueue + Optimistic** | only at save | no || at save (reliable) | low |
167+
| 5 Stateful session | yes, full duration | **yes** | dies on timeout | at open | medium |
168+
| 6 Soft lock + save guard | only at save | no | row lingers | UX at open + data at save | medium |
169+
| 7 **Standard BO draft via EML** | held while draft exists | no | **draft persists, user can resume** | framework handles it | low (no BO to build) |
170+
| 8 **Platform lock manager** | only at save | no | auto-expires via heartbeat | UX at open + data at save | low (if platform ships one) |
171+
172+
---
173+
174+
## 11. Choosing a strategy
175+
176+
Use this flow:
177+
178+
```
179+
Does the app edit data at all?
180+
├── No → render as read-only (every input with enabled = abap_false)
181+
└── Yes
182+
├── On modern S/4 / Steampunk, and a released, draft-enabled SAP BO
183+
│ already covers this object?
184+
│ └── Scenario 7 (Standard BO draft via EML)
185+
├── Does your platform ship a lock manager class?
186+
│ └── Scenario 8 (Platform lock manager)
187+
├── Need "locked by X" feedback at open?
188+
│ ├── Few users, GUI-like feel → Scenario 5
189+
│ └── Many users → Scenario 6
190+
└── Default high-scale stateless editing
191+
└── Scenario 4 (Enqueue + Optimistic)
31192
```
32193

33-
A complete example is in sample `Z2UI5_CL_DEMO_APP_350`.
194+
---
195+
196+
## 12. Common gotchas
197+
198+
- **Don't hold an enqueue across roundtrips without `set_session_stateful( )`.** It will be silently released the moment the HTTP response is sent.
199+
- **Always release the enqueue on every code path** — both success and error. A leaked enqueue blocks future users until session timeout.
200+
- **Soft locks need cleanup.** Without a reaper job or `onbeforeunload` release, you will accumulate stale "edited by" rows.
201+
- **Optimistic timestamps require a field that always updates.** If anyone writes to `VBAK` bypassing `AEDAT/AEZET`, your check will miss real conflicts. Prefer a real timestamp column (`UPDATE_TMSTMP`) when available.
202+
- **Statefulness is contagious.** Once `set_session_stateful( )` is on, every roundtrip costs a work process slot until you turn it off again. Always pair it with an explicit `set_session_stateful( abap_false )` on exit.
203+
- **Always include the optimistic check** in non-draft scenarios. It is the only mechanism that catches conflicts originating *outside* your app (SE16, batch, RFC, another transaction). Draft-enabled BOs (Scenario 7) handle this for you via the framework's ETag.
204+
205+
---
206+
207+
## 13. Summary
208+
209+
| If you need... | Use |
210+
|---|---|
211+
| Personal sandbox or demo where conflicts are impossible | Scenario 1 |
212+
| Quick edits, low contention, no fanciness | Scenario 2 |
213+
| Stateless edits with reliable conflict detection | Scenario 3 |
214+
| Stateless edits, production-grade default | **Scenario 4** |
215+
| GUI-like "lock on open" for internal apps | Scenario 5 |
216+
| UX feedback "locked by Alice" via your own Z table | Scenario 6 |
217+
| A released, draft-enabled SAP BO already exists — just consume it | **Scenario 7** |
218+
| Platform already ships a lock manager — use the standard | **Scenario 8** |
34219

35-
### Other Options
36-
Stateful sessions are only available on private and on-premise systems. For other deployments, infinite backend sessions can hold locks while the UI5 app keeps talking statelessly. See [Statefulness, Locks](../../advanced/stateful.md) for the alternatives and trade-offs.
220+
There is no single "best" lock strategy — only the one that fits your scenario. On a modern S/4 / Steampunk stack, the first question is "does a released SAP BO already cover this object?" — if yes, **Scenario 7** is almost always the right answer. Otherwise start with **Scenario 4** as the safe stateless default; if your platform ships a lock manager, prefer **Scenario 8**; reach for the others when the requirements push you there.

0 commit comments

Comments
 (0)