I have product table with id, name and stock as shown below.
product table:
| id | name | stock |
|---|---|---|
| 1 | Apple | 10 |
| 2 | Orange | 20 |
Then, after T1 runs SELECT FOR UPDATE, T2 needs to wait for T1 to commit for a long time to run SELECT FOR UPDATE as shown below because SELECT FOR UPDATE doesn't have timeout by default:
| Flow | Transaction 1 (T1) | Transaction 2 (T2) | Explanation |
|---|---|---|---|
| Step 1 | BEGIN; |
T1 starts. | |
| Step 2 | BEGIN; |
T2 starts. | |
| Step 3 | SELECT stock FROM product WHERE id = 2 FOR UPDATE;20 |
With "SELECT FOR UPDATE", T1 reads 20. |
|
| Step 4 | SELECT stock FROM product WHERE id = 2 FOR UPDATE; |
T2 needs to wait for T1 to commit to read stock with "SELECT FOR UPDATE". |
|
| Step 5 | Waiting... | ... | |
| Step 6 | Waiting... | ... | |
| Step ... | Waiting... | ... | |
| Step ... | Waiting... | ... | |
| Step ... | Waiting... | ... | |
| Step 98 | COMMIT; |
Waiting... | T1 commits. |
| Step 99 | SELECT stock FROM product WHERE id = 2 FOR UPDATE;20 |
Now with "SELECT FOR UPDATE", T2 reads 20 |
|
| Step 100 | COMMIT; |
T2 commits. |
Now, I want T2 to rollback 3 seconds after T2 waits for T1 as shown below:
| Flow | Transaction 1 (T1) | Transaction 2 (T2) | Explanation |
|---|---|---|---|
| Step 1 | BEGIN; |
T1 starts. | |
| Step 2 | BEGIN; |
T2 starts. | |
| Step 3 | SELECT stock FROM product WHERE id = 2 FOR UPDATE;20 |
With "SELECT FOR UPDATE", T1 reads 20. |
|
| Step 4 | SELECT stock FROM product WHERE id = 2 FOR UPDATE; |
T2 needs to wait for T1 to commit to read stock with "SELECT FOR UPDATE". |
|
| Step 5 | Waiting... | ... | |
| Step 6 | Waiting... | ... | |
| Step 7 | ROLLBACK; | T2 rollbacks 3 seconds after T2 waits for T1. | |
| Step ... | |||
| Step ... | |||
| Step 98 | |||
| Step 99 | |||
| Step 100 | COMMIT; |
T1 commits. |
So, how can I set the timeout of 3 seconds for SELECT FOR UPDATE in transaction in PostgreSQL?
Take a look at this answer: https://stackoverflow.com/a/20963803/8963723