How to manually lock and unlock a row?

2019-08-04 11:59发布

问题:

I am trying to circumvent double-writes by locking and unlocking certain rows.

I have a table personnel and as soon as a user tries to edit a row, I want to lock that row.

So

BEGIN;
// I guess I have to lock it somehow here
SELECT * FROM personnel WHERE id = 12;
COMMIT;

and once an edit as been made, I want to submit the UPDATE in the same style:

BEGIN;
//Unlocking
UPDATE personnel SET ...
WHERE id = 12;
COMMIT;

In the time between, when another user tries to edit the same row, he would get a message.

回答1:

Locks are released at the end of a transaction. So you need to keep the transaction open to uphold the lock and do everything in a single transaction:

BEGIN;
SELECT * FROM personnel WHERE id = 12 FOR UPDATE NOWAIT;  -- row level locking
COMMIT;

BEGIN;
UPDATE personnel SET ...
WHERE id = 12;
COMMIT;

Alternatively you can use the somewhat less restrictive FOR SHARE clause.
Details in the manual on SELECT in the chapter "The Locking Clause".

Concurrent reads are allowed. Quoting the chapter "Row-level Locks" in the manual:

In addition to table-level locks, there are row-level locks, which can be exclusive or shared locks. An exclusive row-level lock on a specific row is automatically acquired when the row is updated or deleted. The lock is held until the transaction commits or rolls back, just like table-level locks. Row-level locks do not affect data querying; they block only writers to the same row.

To have concurrent attempts to do the same fail immediately, use the NOWAIT option - for all competing queries.