mysql:tx:locking
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| mysql:tx:locking [2026/05/16 08:00] – phong2018 | mysql:tx:locking [2026/05/16 08:09] (current) – [1 Read Lock (Shared Lock)] phong2018 | ||
|---|---|---|---|
| Line 6: | Line 6: | ||
| Read lock (Shared) - FOR SHARE → I am reading, others can read too, but no one can write | Read lock (Shared) - FOR SHARE → I am reading, others can read too, but no one can write | ||
| + | |||
| Write lock (Exclusive) - FOR UPDATE → I am about to update, no one else can touch this row | Write lock (Exclusive) - FOR UPDATE → I am about to update, no one else can touch this row | ||
| ---- | ---- | ||
| - | ==== 1 Read Lock (Shared Lock) ==== | + | ==== 1. Read Lock (Shared Lock) ==== |
| Allows multiple transactions to read the same row at the same time, | Allows multiple transactions to read the same row at the same time, | ||
| Line 104: | Line 105: | ||
| SELECT balance FROM accounts WHERE id = 1 FOR UPDATE; | SELECT balance FROM accounts WHERE id = 1 FOR UPDATE; | ||
| </ | </ | ||
| + | |||
| + | ==== Options after FOR UPDATE ==== | ||
| + | |||
| + | By default, '' | ||
| + | MySQL provides two modifiers to change this behavior. | ||
| + | |||
| + | <code sql> | ||
| + | -- 1. Default — wait until lock is released (blocking) | ||
| + | SELECT * FROM accounts WHERE id = 1 FOR UPDATE; | ||
| + | |||
| + | -- 2. NOWAIT — if row is locked, throw error immediately, | ||
| + | SELECT * FROM accounts WHERE id = 1 FOR UPDATE NOWAIT; | ||
| + | |||
| + | -- 3. SKIP LOCKED — if row is locked, skip it and return next free row | ||
| + | SELECT * FROM accounts WHERE id = 1 FOR UPDATE SKIP LOCKED; | ||
| + | </ | ||
| + | |||
| + | ---- | ||
| + | |||
| + | === NOWAIT === | ||
| + | |||
| + | Use when you want to try locking but **fail fast** if someone else already holds the lock. | ||
| + | The application catches the error and responds immediately — no waiting. | ||
| + | |||
| + | <code sql> | ||
| + | BEGIN; | ||
| + | |||
| + | SELECT balance FROM accounts WHERE id = 1 | ||
| + | FOR UPDATE NOWAIT; | ||
| + | -- If row is already locked by another transaction: | ||
| + | -- ERROR 3572: Statement aborted because lock(s) could not be acquired | ||
| + | -- Error thrown immediately — app catches and shows " | ||
| + | |||
| + | COMMIT; | ||
| + | </ | ||
| + | |||
| + | **When to use:** | ||
| + | * APIs where waiting is unacceptable — fail fast is better than a slow timeout. | ||
| + | * Optimistic workflows where conflict is rare — if locked, just retry. | ||
| + | * Showing a user-friendly message instead of hanging the request. | ||
| + | |||
| + | ---- | ||
| + | |||
| + | === SKIP LOCKED === | ||
| + | |||
| + | Use when you want to skip locked rows and move on to the next available one. | ||
| + | Perfect for **job queues** — multiple workers process rows in parallel | ||
| + | without stepping on each other. | ||
| + | |||
| + | <code sql> | ||
| + | -- Worker picks the next available pending job | ||
| + | -- Skips any rows already being processed by other workers | ||
| + | BEGIN; | ||
| + | |||
| + | SELECT * | ||
| + | FROM jobs | ||
| + | WHERE status = ' | ||
| + | ORDER BY id | ||
| + | LIMIT 1 | ||
| + | FOR UPDATE SKIP LOCKED; | ||
| + | -- If top row is locked by Worker 2 → skipped automatically | ||
| + | -- Returns the next unlocked row immediately | ||
| + | |||
| + | COMMIT; | ||
| + | </ | ||
| + | |||
| + | **When to use:** | ||
| + | * Job queues — multiple workers run in parallel, each picks a different row. | ||
| + | * Task processing systems — avoid two workers picking the same task. | ||
| + | * Any scenario where "next available" | ||
| + | |||
| + | ---- | ||
| + | |||
| + | === Comparison === | ||
| + | |||
| + | ^ Syntax | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | |||
| + | ---- | ||
| + | |||
| + | === Laravel Syntax === | ||
| + | |||
| + | <code php> | ||
| + | // Default — wait for lock | ||
| + | Account:: | ||
| + | |||
| + | // NOWAIT — throw error if locked | ||
| + | Account:: | ||
| + | |||
| + | // SKIP LOCKED — skip locked rows, return next free row | ||
| + | Job:: | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | </ | ||
| + | |||
| + | ---- | ||
| + | |||
| + | > **Note:** '' | ||
| + | > instead of blocking, it moves on to the next unlocked row. | ||
| + | > However it still acquires a lock on the row it returns — | ||
| + | > it is not a lock-free read. | ||
| ---- | ---- | ||
| - | ==== 3 Lock Compatibility Matrix ==== | + | ==== 3. Lock Compatibility Matrix ==== |
| Shows whether two locks can be held simultaneously on the same row. | Shows whether two locks can be held simultaneously on the same row. | ||
| Line 192: | Line 298: | ||
| ---- | ---- | ||
| - | ==== 6 Row Lock vs Table Lock ==== | + | ==== 6. Row Lock vs Table Lock ==== |
| ^ Feature | ^ Feature | ||
mysql/tx/locking.1778918417.txt.gz · Last modified: by phong2018
