У меня есть три таблицы в моей базе данных (MySQL / InnoDB): pupil
, evening_activity
а также pupil_evening_activity
, Как вы можете догадаться, есть m:m
отношения между pupil
а также evening_activity
,
У меня есть HTML-форма для вставки новых учеников и ассоциирования с ними вечерних мероприятий. После отправки формы я хотел бы добавить учеников и связанные с ними виды деятельности в базу данных. Итак, я написал этот код:
$db = new PDO('mysql:host=localhost;dbname=school;charset=utf8','root', '****');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);try {
$sql = "INSERT INTO pupil
(name, surname)
VALUES
('test_name', 'test_surname')";
$st = $db->prepare($sql);
$st->execute();
foreach ($eveningActivityIds as $eveningActivityId) {
$sql = "INSERT INTO pupil_evening_activity
(pupil_id, evening_activity_id)
VALUES
(?, ?)
";
$st = $db->prepare($sql);
$st->execute(array($db->lastInsertId(), $eveningActivityId));
}
} catch (PDOException $e) {
echo $e->getMessage();
return false;
}
Я написал этот код ожидая PDO::lastInsertId()
всегда возвращает последний вставленный идентификатор ученика, но я обнаружил, что это действительно возвращает последний вставленный id
на всю базу данных. Так что, если в гипотетический вставлен другой ряд teacher
Таблица как раз перед призывая к $db->lastInsertId()
в коде выше, $db->lastInsertId()
вернет id
вставленного учителя вместо id
последнего ученика.
Итак, как я могу получить 100% безопасность последней вставленной id
из pupil
стол после отправки формы?
Я думал об использовании транзакции и MAX()
функция, чтобы получить последний id
вставлен в pupil
стол, но я не уверен в этом.
Ошибочно иметь $ db-> lastInsertId () в цикле foreach, так как он может возвращать непредсказуемые значения. Пожалуйста, рассмотрите код ниже:
try {
$sql = "INSERT INTO pupil
(name, surname)
VALUES
('test_name', 'test_surname')";
$st = $db->prepare($sql);
$st->execute();
// save pupil id into variable here:
$pupil_id = $db->lastInsertId();
// also there's no need to prepare the statement on each iteration:
$sql = "INSERT INTO pupil_evening_activity
(pupil_id, evening_activity_id)
VALUES
(?, ?)";
$st = $db->prepare($sql);
foreach ($eveningActivityIds as $eveningActivityId) {
$st->execute(array($pupil_id, $eveningActivityId));
}
} catch (PDOException $e) {
echo $e->getMessage();
return false;
}
Оптимизация: вы можете вставить все действия в одном утверждении. Это экономит несколько запросов
try {
$sql = "INSERT INTO pupil
(name, surname)
VALUES
('test_name', 'test_surname')";
$st = $db->prepare($sql);
$st->execute();
// save pupil id into variable here:
$pupil_id = $db->lastInsertId();
$sql = 'INSERT INTO pupil_evening_activity
(pupil_id, evening_activity_id)
VALUES ';
$values = array();
foreach ($eveningActivityIds as $eveningActivityId) {
$sql .= '(?, ?),';
array_push($values, $pupil_id, $eveningActivityId);
}
$st = $db->prepare(chop($sql, ','));
$st->execute($values);
} catch (PDOException $e) {
echo $e->getMessage();
return false;
}
Других решений пока нет …