Loading...

Допустим у меня такой пример
php
<?php
db::exec("INSERT INTO log(ip, action) VALUES ('xxx', 'yyy')";
sleep(rand(10, 60)); # Некая ресурсоёмкая задача
# А тут мне надо получить id этой записи
$last = db::fetch("SELECT id FROM log ORDER BY id DESC LIMIT 1");

Возможен ли вариант что во время "sleep" какой-нибудь другой юзер добавит еще одну свою запись и я в $last получу левый id ? Если да, то как этого избежать? Как заблокировать таблицу от изменений во время работы скрипта?
https://www.php.net/manual/ru/pdo.lastinsertid.php
Те же яйца только в профиль. Я про блокировку спросил
Something (16 авг 2023, в 11:09)
Те же яйца только в профиль. Я про блокировку спросил
командой LOCK TABLES
Потом UNLOCK после выполнения
Something (16 авг 2023, в 9:25)
Допустим у меня такой пример
php
<?php
db::exec("INSERT INTO log(ip, action) VALUES ('xxx', 'yyy')";
sleep(rand(10, 60)); # Некая ресурсоёмкая задача
# А тут мне надо получить id этой записи
$last = db::fetch("SELECT id FROM log ORDER BY id DESC LIMIT 1");

Возможен ли вариант что во время "sleep" какой-нибудь другой юзер добавит еще одну свою запись и я в $last получу левый id ? Если да, то как этого избежать? Как заблокировать таблицу от изменений во время работы скрипта?
https://www.php.net/manual/en/pdo.begintransaction.php
php
<?php
db::beginTransaction();
db::exec("INSERT INTO log(ip, action) VALUES ('xxx', 'yyy')";
sleep(rand(10, 60));
$last = db::fetch("SELECT id FROM log ORDER BY id DESC LIMIT 1");
db::commit();

________
посл. ред. 16.08.2023 в 11:19; всего 1 раз(а); by mrcatoff
FullTwo [!] (16 авг 2023, в 11:18)
командой LOCK TABLES
Потом UNLOCK после выполнения
Вот это походу то что надо. А если где-то между локом и анлоком скрипт сдохнет (например из-за fatal error), то база останется заблокированной?
mrcatoff
Адм
(16 авг 2023, в 11:19)
https://www.php.net/manual/en/pdo.begintransaction.php
php
<?php
db::beginTransaction();
db::exec("INSERT INTO log(ip, action) VALUES ('xxx', 'yyy')";
sleep(rand(10, 60));
$last = db::fetch("SELECT id FROM log ORDER BY id DESC LIMIT 1");
db::commit();
Тоже думал про транзакции. Ты уверен что при транзакции таблица блокируется? В доках про блокировку не написано
________
посл. ред. 16.08.2023 в 11:36; всего 2 раз(а); by Something
Something (16 авг 2023, в 11:33)
Вот это походу то что надо. А если где-то между локом и анлоком скрипт сдохнет (например из-за fatal error), то база останется заблокированной?
Пока не будет unlock

Ты повесил замок, пока не откроешь не попадешь
Something (16 авг 2023, в 11:09)
Те же яйца только в профиль. Я про блокировку спросил
Это не тоже самое, ты берешь из всей таблицы записи, а в случае с функцией, тебе вернется ид самой записи и не важно, были записи или нет
https://ru.stackoverflow.com/questions/453648/Какой-id-верн...nsertid-из-pdo
Ты не только про блокировку спрашивал
Я ответила оптимальный вариант для получения ид
Зачем блокировать всю таблицу?
________
посл. ред. 16.08.2023 в 14:46; всего 1 раз(а); by Лара
Something (16 авг 2023, в 9:25)
Допустим у меня такой пример
php
<?php
db::exec("INSERT INTO log(ip, action) VALUES ('xxx', 'yyy')";
sleep(rand(10, 60)); # Некая ресурсоёмкая задача
# А тут мне надо получить id этой записи
$last = db::fetch("SELECT id FROM log ORDER BY id DESC LIMIT 1");

Возможен ли вариант что во время "sleep" какой-нибудь другой юзер добавит еще одну свою запись и я в $last получу левый id ? Если да, то как этого избежать? Как заблокировать таблицу от изменений во время работы скрипта?
Да, в данном коде есть вероятность того, что во время выполнения sleep какой-либо другой пользователь добавит запись в таблицу log, и ты можеш получить неправильный ID в переменной $last. Это связано с тем, что блокировка таблицы может быть применена для предотвращения таких конфликтов.

Чтобы избежать этой ситуации, ты можеш воспользоваться механизмами транзакций и блокировок в базе данных. В большинстве систем управления базами данных (СУБД) есть поддержка транзакций и блокировок, которые позволяют контролировать доступ к данным в многопользовательской среде.

Тебе нужно выполнить следующие шаги:

Начать транзакцию: Перед выполнением INSERT запроса начни транзакцию. Это предотвратит доступ других пользователей к данным до завершения транзакции.

Выполнить INSERT внутри транзакции: Выполните INSERT запрос внутри начатой транзакции.

Выполнить SELECT внутри транзакции: Также выполните SELECT запрос для получения ID внутри транзакции.

Завершить транзакцию: После выполнения всех операций (включая sleep), заверши транзакцию. Это позволит другим операциям получить доступ к данным.

Примерно так это может выглядеть в коде:
php
<?php
$db = new PDO("your_database_connection_details");

try {
$db->beginTransaction();

$insertQuery = "INSERT INTO log(ip, action) VALUES ('xxx', 'yyy')";
$db->exec($insertQuery);

sleep(rand(10, 60)); // Некая ресурсоёмкая задача

$selectQuery = "SELECT id FROM log ORDER BY id DESC LIMIT 1";
$last = $db->query($selectQuery)->fetchColumn();

$db->commit();
} catch (Exception $e) {
$db->rollBack();
// Обработка ошибки
}
?>


Здесь используем транзакции для обеспечения целостности данных и блокировки таблицы во время выполнения операций. Важно отметить, что использование транзакций может варьироваться в зависимости от типа базы данных, который ты используете.
Онлайн: 5
Время:
Gen. 0.104
(c) Bym.Guru 2010-2025