问题
Assume that we have a table with the following schema:
CREATE TABLE Persons (
sid int NOT NULL AUTO_INCREMENT,
groupName varchar(255) NOT NULL,
userIdInGroup int,
PRIMARY KEY (sid));
We want to assign each new user in the same group an auto-increment userId based on the last userId of the group, i.e. we want to emulate an auto-increment userId within each group.
Since we are inserting the new userId considering the MAX(userIdInGroup) we need to wrap select and insert in a transaction. Something like this:
START TRANSACTION
SET @a = (SELECT MAX(userIdInGroup) FROM Persons WHERE groupName= 'Foo') +1;
INSERT THE NEW ROW USING userIdInGroup = @a
COMMIT
- Is just selecting MAX in a transaction safe or do we need to lock something by SELECT FOR UPDATE?
- Is there anyway to bypass transaction and still be consistent?
回答1:
I'm not a MySql person, but I do have enough experience with other databases to know that this is a really bad idea. This UserIdInGroup
can easily be calculated using row_number
:
SELECT sid,
groupName,
ROW_NUMBER() OVER(PARTITION BY groupName ORDER BY sid) AS userIdInGroup
FROM Persons
And besides the fact that rolling your own auto-increment usually ends up giving wrong numbers (especially in a multi-threaded environment), what you can calculate easily (both in the code and in the performance aspect) should not be stored anyway.
来源:https://stackoverflow.com/questions/54341289/fastest-and-safest-way-to-emulate-auto-increment-using-max-in-innodb