Example 1
Reserve available inventory within a transaction
The SELECT FOR UPDATE locks row 1 exclusively. Any other transaction trying to read the same row FOR UPDATE (or to UPDATE it) will block until this transaction commits. After the UPDATE, qty drops from 5 to 4. The COMMIT releases the lock. Without the lock, two concurrent sessions could both read qty=5, both decrement to 4, and write 4 — losing one decrement.
CREATE TABLE inventory (id INT PRIMARY KEY, item VARCHAR(50), qty INT);
INSERT INTO
inventory
VALUES
(1, 'Widget', 5),
(2, 'Gadget', 0);BEGIN;
SELECT
id,
item,
qty
FROM
inventory
WHERE
id = 1 FOR
UPDATE;
UPDATE inventory
SET
qty = qty - 1
WHERE
id = 1;
COMMIT;
SELECT
id,
item,
qty
FROM
inventory
ORDER BY
id;| id | item | qty |
|---|---|---|
| 1 | Widget | 4 |
| 2 | Gadget | 0 |
CREATE TABLE inventory (id INT PRIMARY KEY, item VARCHAR(50), qty INT);
INSERT INTO
inventory
VALUES
(1, 'Widget', 5),
(2, 'Gadget', 0);BEGIN TRANSACTION;
SELECT
id,
item,
qty
FROM
inventory
WITH
(UPDLOCK, ROWLOCK)
WHERE
id = 1;
UPDATE inventory
SET
qty = qty - 1
WHERE
id = 1;
COMMIT;
SELECT
id,
item,
qty
FROM
inventory
ORDER BY
id;| id | item | qty |
|---|---|---|
| 1 | Widget | 4 |
| 2 | Gadget | 0 |
SQL Server uses WITH (UPDLOCK, ROWLOCK) instead of FOR UPDATE. SQLite does not support row-level locking. Final inventory state is identical across supported engines.