The flow for locking I have currently is a SELECT ... FOR UPDATE
followed by an INSERT
. e.g.
BEGIN;
SELECT count(*) FROM test WHERE col = 1 FOR UPDATE;
# check to ensure an invariant will still be met after the insert.
INSERT INTO test (col) VALUES (1);
COMMIT;
I expected the SELECT
above to acquire an exclusive lock on something to prevent multiple callers from being in the critical section at the same time but it appears that by default, InnoDB only acquires a shared lock on a table or index gap. If two concurrent transactions attempt this at the same time, they can both acquire the shared lock but one will fail with a deadlock error when trying to insert.
Is there any way to make this code behave more like standard pessimistic locking to prevent concurrent readers?
Note: I am aware that in some cases, a unique index can solve this issue but I have come across two instances where a unique index is insufficient (1) when one of the columns is nullable and I want exactly one null value and (2) when I want to guarantee another invariant about the rows like there should be less than 10 rows with a given key.