Здравствуйте. Есть задача при каждом обращении к функции PHP возвращать из базы уникальное значение ячейки и после этого его инкрементировать. Честно, не знаю как заблокировать таблицу до изменения этого значения, чтоб не вернуть несколько раз одно и то же значение. Попробовал написать так: function AutoIncrement() { global $DB; $stmt = $DB->DBH->prepare("SELECT ai_dt FROM ".$this->Table." WHERE num_dt=:num_dt FOR UPDATE"); $stmt->execute(array('num_dt' => $this->ID)); $AutoIncrement = $stmt->fetchColumn(); $stmt = $DB->DBH->prepare("UPDATE ".$this->Table." SET ai_dt=ai_dt+1 WHERE num_dt=:num_dt"); $stmt->execute(array('num_dt' => $this->ID)); return $AutoIncrement; } Но бывает иногда возвращается одно значение пару раз. Подскажите пожалуйста как правильно это сделать?
PHP: <?php function AutoIncrement($dbh) { /*Begin a transaction, turning off autocommit */ $dbh->beginTransaction(); $stmt = $dbh->prepare("SELECT ai_dt FROM ".$this->Table." WHERE num_dt=:num_dt FOR UPDATE"); $stmt->execute(array('num_dt' => $this->ID)); $AutoIncrement = $stmt->fetchColumn(); $stmt = $dbh->prepare("UPDATE ".$this->Table." SET ai_dt=ai_dt+1 WHERE num_dt=:num_dt"); $stmt->execute(array('num_dt' => $this->ID)); /*Commit the changes*/ $dbh->commit(); return $AutoIncrement; } https://phpize.online/sql/mysql57/undefined/php/php81/fd62d4c5c59aff2b3f739115c0ecaf1c/
Спасибо. Все получилось как нужно) Только я добавил обработку ошибок и rollBack PHP: function AutoIncrement() { global $DB; $AutoIncrement = false; try { $DB->DBH->beginTransaction(); $stmt = $DB->DBH->prepare("SELECT ai_dt FROM ".$this->Table." WHERE num_dt=:num_dt FOR UPDATE"); $stmt->execute(array('num_dt' => $this->ID)); $AutoIncrement = $stmt->fetchColumn(); $stmt = $DB->DBH->prepare("UPDATE ".$this->Table." SET ai_dt=ai_dt+1 WHERE num_dt=:num_dt"); $stmt->execute(array('num_dt' => $this->ID)); $DB->DBH->commit(); } catch (Exception $e) { $DB->DBH->rollBack(); echo "Ошибка Sessions Transaction: " . $e->getMessage(); } return $AutoIncrement; }
Просто для информации скажу, автоинкремент в базе не завязан на транзакции. Даже если изменения будут откачены по rollback, счетчик увеличится. Это принципиально и это очень верно. ))) Я бы не стал без крайней необходимости эмулировать автоинкремент другими средствами. Лучше полагаться на автоинкрементное поле. Ну или на "генератор" в некоторых диалектах SQL, если он доступен отдельно от айдентити поля. @Goga_77 не расскажешь про изначальную задачу? Возможно ты слишком сузил свой выбор этой идеей про "апдейт с блокировкой".
Этот аутоинкремент, нахордится в моей библиотеке сессий (переменные пользователя) и он генерит ID для элементов HTML для аякса. Если происходит одновременное чтение этого значения несколькими запросами до того как поле обновится, получается что одно значение присваивается нескольким элементам HTML. В результате, нажимаешь кнопочку вызывающую всплывающее окно, а окошко всплывает в другом месте.
@artoodetoo, обычный числовой он самый простой. И походу у него свой счетчик для каждого юзера. @Goga_77, у мускула есть прикольная фишка для этого. Транзакцию городить не нужно.
Вот если есть зависимость от юзера, значит надо проектировать так, чтобы реализовать эту зависимость. (правда не знаю почему ты это предположил) Я думаю что буквально для "ID для элементов HTML для аякса" подойдет счетчик $i++ в коде. Он даст уникальность в пределах одного запроса. Если нужна уникальность в пределах сессии — внезапно™ надо этот $i хранить в сессии! И есть ID самой сессии, который можно генерировать любым генератором больших случайных ID. Например uniqid() --- Добавлено --- P.S. Пока разраб не приучится четко формулировать вопросы, он не сможет писать грамотный и чистый код. Это 100% инфа.
WHERE, «библиотека сессий» и т.п. Или счетчик у юзера, на основе которого генерятся ID для элементов HTML. Или и того хуже – счетчик у каждого элемента каждого юзера. Походу речь о версионности. Так что «уникальность в пределах одного запроса» не подходит. Тут согласен на 100% --- Добавлено --- Можно, конечно, накручивать при каждом запросе, получающем ответ «не из кеша», но это как-то криво.
ID генерится для элементов HTML естественно не для одного запроса а для страницы с которой запросы летают на сервер. Денные сессии лежат в базе, в поле с данными, в таблице, в соседнем поле кручу счетчик. Все получилось, все работает, очень удобно. Спасибо)
Окей. Данные сессии... и в соседнем поле... То есть это счетчик внутри одной сессии. Ээээ... нууу это кагбэ ни на что тебе не намекает? Ещё для общей информации: дефолтовый пхп-шный механизм сессии использует блокировку. То есть если у тебя пересеклись > 1 запроса, то в каждый момент времени данные сессии может получить только один из них, остальные ждут. То же самое ты переизобретаешь со своей новой сущностью.
Намекает) Штатные сессии не использую, не нравится, там же не только счетчик) Пользуюсь собственным классом.