Как бороться с дублированием идентификаторов в многопользовательском приложении без использования на уровне таблицы?
Представьте себе банальную реляционную структуру с целочисленными идентификаторами, не несущими смысловой нагрузки. Ну и надо написать web-приложение с этой базой работающее (в т.ч. добавляющее новые элементы). Автоинкремент на уровне определения таблицы использовать нельзя. Приложение многопользовательское, так что если просто запросить максимальный ID ситуация с ним может измениться быстрее, чем ты успеешь отправить запрос на вставку на основе этой информации. Какие тут есть варианты? Никаких библиотек типа ORM / Persistance не используем.
Язык PHP выбран условно как наиболее всем понятный, в принципе можно любой другой, главное - чтобы из ответа была видна вся логика (а не просто "берём библиотеку такую-то и она обо всём позаботится сама") и её можно было без проблем реализовать на, грубо говоря, любом языке.
The ID that was generated is maintained in the server on a per-connection basis. This means that the value returned by the function to a given client is the first AUTO_INCREMENT value generated for most recent statement affecting an AUTO_INCREMENT column by that client. This value cannot be affected by other clients, even if they generate AUTO_INCREMENT values of their own. This behavior ensures that each client can retrieve its own ID without concern for the activity of other clients, and without the need for locks or transactions.
Так что запросы других клиентов никак не повлияют на результат.
Во-первых это value of the AUTOINCREMENT column for the last INSERT, а у нас нет AUTOINCREMENT column на уровне БД вообще. Во-вторых per-connection basis означает, что после закрытия коннэкшена (что по идее делается после каждого запроса за исключением вариантов с коннекшн-пулами и случаев, когда надо скопом внести кучу изменений и открывать-закрывать соединения - не оптимально) теряет смысл.
@StrangeAttractor: так а почему вы не хотите использовать auto increment? Тогда при смотритесь к транзакциям. Но это может сильно просадить производительность.
@StrangeAttractor: нет, Вы не правы - соединение разрывается либо когда Ваш скрипт завершил работу, либо вручную с помощью специального метода msqli(или PDO)
@StrangeAttractor: тогда извинюсь ) открытие соединения с бд - дорогая операция, поэтому лучше закрывать, когда вы все сделали. Но в таком случае в список дел можно внести и запрос на получение last id и все от работает как надо)
@StrangeAttractor: непонятен буквальный догматизм, который противоречит смыслу описанного алгоритма "сделал дело - закрой коннекшн". Если "дело" включает в себя получение сгенерированного айди, то что мешает сначала доделать "дело", получив нужные данные, и только потом уже закрывать коннект? Вся задача (в том виде, в котором она описана) выглядит нагромождением беспочвенных капризов и немотивированых ограничений, в результате которых предлагается изобретать велосипед на квадратных колесах. Если уж хотите делать нормально, то потрудитесь описать причины.
Вариант в лоб - сделать свою таблицу для хранения текущих счетчиков.
В транзакции UPDATE ids SET id = id + 1, SELECT ids.id
И полученный id используете для вставки.
Или использовать для хранения счетчиков redis.
если просто запросить максимальный ID ситуация с ним может измениться быстрее, чем ты успеешь отправить запрос на вставку на основе этой информации. Какие тут есть варианты?
INSERT ....IF NOT EXISTS(....)
одна транзакция, а они - последовательные.