I have an InnoDB table containing users, like this:
+--------------+-----------------------+
| user_id | name |
+--------------+-----------------------+
| 1 | Bob |
| 1 | Marry |
| 2 | Bob |
| 1 | John |
| 3 | Bob |
| 2 | Marry |
+--------------+-----------------------+
On each insert I increment user_id by 1 so for example, the next user_id for Bob will be 4
I use this query to do that:
INSERT INTO users (user_id, name)
SELECT 1 + coalesce((SELECT max(user_id) FROM users WHERE name='Bob'), 0), 'Bob';
Now I need to make sure that two different users don't add a 'Bob' at the same time. I don't want any two Bobs with user_id 4. Each of Bob's user ids must be different.
Is is possible to write and update lock all of Bob's rows when the above insert query is run? I cannot lock the whole table because many other users still need full access to their rows. Also, all rows should be readable at all times. How would I do this?
To solve the first part of your question, create a unique index on user_id and name.
That will prevent duplicate user_id,name records.
The answer to this question is the same as this one. InnoDB will lock more rows here than you expect for safety with statement-based binary logging.
The solution: use row based binary logging with the read-committed isolation level.
Assuming InnoDB here, you can use SELECT ... LOCK IN SHARE MODE to lock the rows when you select them.