За последние 24 часа нас посетили 17463 программиста и 1715 роботов. Сейчас ищут 1711 программистов ...

Как сделать типа аутоинкремент в одной строчке?

Тема в разделе "PHP и базы данных", создана пользователем Goga_77, 20 дек 2022.

  1. Goga_77

    Goga_77 Новичок

    С нами с:
    20 дек 2022
    Сообщения:
    5
    Симпатии:
    1
    Здравствуйте.
    Есть задача при каждом обращении к функции 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;
    }

    Но бывает иногда возвращается одно значение пару раз.
    Подскажите пожалуйста как правильно это сделать?
     
  2. Slava Rozhnev

    Slava Rozhnev Новичок

    С нами с:
    6 сен 2021
    Сообщения:
    87
    Симпатии:
    26
    Адрес:
    https://phpize.online
    PHP:
    1. <?php
    2. function AutoIncrement($dbh) {
    3.     /*Begin a transaction, turning off autocommit */
    4.     $dbh->beginTransaction();
    5.    
    6.     $stmt = $dbh->prepare("SELECT ai_dt FROM ".$this->Table." WHERE num_dt=:num_dt FOR UPDATE");
    7.     $stmt->execute(array('num_dt' => $this->ID));
    8.     $AutoIncrement = $stmt->fetchColumn();
    9.     $stmt = $dbh->prepare("UPDATE ".$this->Table." SET ai_dt=ai_dt+1 WHERE num_dt=:num_dt");
    10.     $stmt->execute(array('num_dt' => $this->ID));
    11.    
    12.     /*Commit the changes*/
    13.     $dbh->commit();
    14.  
    15.     return $AutoIncrement;
    16. }
    https://phpize.online/sql/mysql57/undefined/php/php81/fd62d4c5c59aff2b3f739115c0ecaf1c/
     
  3. Sail

    Sail Старожил

    С нами с:
    1 ноя 2016
    Сообщения:
    1.593
    Симпатии:
    362
    С этой задачей успешно база справляется.
    Например, в MySQL: LAST_INSERT_ID()
    Пример в песочнице
     
    miketomlin нравится это.
  4. Goga_77

    Goga_77 Новичок

    С нами с:
    20 дек 2022
    Сообщения:
    5
    Симпатии:
    1
    Спасибо.
    Все получилось как нужно)
    Только я добавил обработку ошибок и rollBack
    PHP:
    1. function AutoIncrement() {
    2.         global $DB;
    3.  
    4.         $AutoIncrement = false;
    5.  
    6.         try {
    7.             $DB->DBH->beginTransaction();
    8.             $stmt = $DB->DBH->prepare("SELECT ai_dt FROM ".$this->Table." WHERE num_dt=:num_dt FOR UPDATE");
    9.             $stmt->execute(array('num_dt' => $this->ID));
    10.             $AutoIncrement = $stmt->fetchColumn();
    11.             $stmt = $DB->DBH->prepare("UPDATE ".$this->Table." SET ai_dt=ai_dt+1 WHERE num_dt=:num_dt");
    12.             $stmt->execute(array('num_dt' => $this->ID));
    13.             $DB->DBH->commit();
    14.          
    15.         } catch (Exception $e) {
    16.             $DB->DBH->rollBack();
    17.             echo "Ошибка Sessions Transaction: " . $e->getMessage();
    18.         }
    19.  
    20.         return $AutoIncrement;
    21.     }
     
    Slava Rozhnev нравится это.
  5. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.108
    Симпатии:
    1.243
    Адрес:
    там-сям
    Просто для информации скажу, автоинкремент в базе не завязан на транзакции. Даже если изменения будут откачены по rollback, счетчик увеличится. Это принципиально и это очень верно. ))) Я бы не стал без крайней необходимости эмулировать автоинкремент другими средствами.
    Лучше полагаться на автоинкрементное поле. Ну или на "генератор" в некоторых диалектах SQL, если он доступен отдельно от айдентити поля.

    @Goga_77 не расскажешь про изначальную задачу? Возможно ты слишком сузил свой выбор этой идеей про "апдейт с блокировкой".
     
  6. Goga_77

    Goga_77 Новичок

    С нами с:
    20 дек 2022
    Сообщения:
    5
    Симпатии:
    1
    Этот аутоинкремент, нахордится в моей библиотеке сессий (переменные пользователя) и он генерит ID для элементов HTML для аякса. Если происходит одновременное чтение этого значения несколькими запросами до того как поле обновится, получается что одно значение присваивается нескольким элементам HTML. В результате, нажимаешь кнопочку вызывающую всплывающее окно, а окошко всплывает в другом месте.
     
  7. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.108
    Симпатии:
    1.243
    Адрес:
    там-сям
    Семен Семеныч! Так тебе надо просто хороший уникальный id. Зачем вообще здесь зависимость от БД?
     
  8. miketomlin

    miketomlin Старожил

    С нами с:
    9 авг 2016
    Сообщения:
    3.839
    Симпатии:
    651
    @artoodetoo, обычный числовой он самый простой. И походу у него свой счетчик для каждого юзера.

    @Goga_77, у мускула есть прикольная фишка для этого. Транзакцию городить не нужно.
     
    #8 miketomlin, 28 дек 2022
    Последнее редактирование: 28 дек 2022
  9. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.108
    Симпатии:
    1.243
    Адрес:
    там-сям
    Вот если есть зависимость от юзера, значит надо проектировать так, чтобы реализовать эту зависимость. (правда не знаю почему ты это предположил)

    Я думаю что буквально для "ID для элементов HTML для аякса" подойдет счетчик $i++ в коде. Он даст уникальность в пределах одного запроса. Если нужна уникальность в пределах сессии — внезапно™ надо этот $i хранить в сессии!
    И есть ID самой сессии, который можно генерировать любым генератором больших случайных ID. Например uniqid()
    --- Добавлено ---
    P.S. Пока разраб не приучится четко формулировать вопросы, он не сможет писать грамотный и чистый код. Это 100% инфа. :)
     
  10. miketomlin

    miketomlin Старожил

    С нами с:
    9 авг 2016
    Сообщения:
    3.839
    Симпатии:
    651
    WHERE, «библиотека сессий» и т.п. Или счетчик у юзера, на основе которого генерятся ID для элементов HTML. Или и того хуже – счетчик у каждого элемента каждого юзера.

    Походу речь о версионности. Так что «уникальность в пределах одного запроса» не подходит.

    Тут согласен на 100% :)
    --- Добавлено ---
    Можно, конечно, накручивать при каждом запросе, получающем ответ «не из кеша», но это как-то криво.
     
  11. Goga_77

    Goga_77 Новичок

    С нами с:
    20 дек 2022
    Сообщения:
    5
    Симпатии:
    1
    ID генерится для элементов HTML естественно не для одного запроса а для страницы с которой запросы летают на сервер. Денные сессии лежат в базе, в поле с данными, в таблице, в соседнем поле кручу счетчик.
    Все получилось, все работает, очень удобно. Спасибо)
     
  12. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.108
    Симпатии:
    1.243
    Адрес:
    там-сям
    Окей. Данные сессии... и в соседнем поле... То есть это счетчик внутри одной сессии. Ээээ... нууу это кагбэ ни на что тебе не намекает?

    Ещё для общей информации: дефолтовый пхп-шный механизм сессии использует блокировку. То есть если у тебя пересеклись > 1 запроса, то в каждый момент времени данные сессии может получить только один из них, остальные ждут. То же самое ты переизобретаешь со своей новой сущностью.
     
  13. Goga_77

    Goga_77 Новичок

    С нами с:
    20 дек 2022
    Сообщения:
    5
    Симпатии:
    1
    Намекает) Штатные сессии не использую, не нравится, там же не только счетчик) Пользуюсь собственным классом.
     
  14. don.bidon

    don.bidon Активный пользователь

    С нами с:
    28 мар 2021
    Сообщения:
    922
    Симпатии:
    143
    У тебя, наверное, PHP4. Сейчас штатные сессии очень гибкие и вменяемые )