Все таблицы - InnoDB.
Вставка данных производится последовательно в 3 разных таблицы. Сначала в таблицу объектов (построек), получаем айдишник, создаем клиента в другой таблице, получаем айдишник, в итоге создаем заказ, в котором указываем айдишники объекта и клиента.
Таблицы "'obje !!! cts" не существует. Если убрать 2 Insert для клиента и заказа, то прилетает Exception, который и говорит, что такой таблицы не существует. Как бы тут откат и не нужен, раз таблицы нет, то вставка в норм таблицу не произвелась.
Сценарий второй. 2 insert'ы приведенные в примере остаются на месте. Ошибка в названии первой таблицы присутствует. Блок catch срабатывает, т.к. $result возвращает по прежнему ту же ошибку, но не срабатывает rollback. В таблицу клиентов и заказов данные вставляются. И условно когда id'шники в заказах должны были быть как (189, 189, 189), по факту оказывается как (189, 189, 0) т.к. lastID от ошибочной таблицы возвращает false.
Я может недополнял, но по идее всё же должно откатиться, если в блоке try произошла ошибка? Нужно обязательно записать 3 таблицы и в такой последовательности. Без возвращенных адекватных айдишников таблицы не связать.
function create(array $data)
{
try {
// Начинаем транзакцию
$this->DBH->beginTransaction();
// Исполняем запросы
// Объект
$objectInsertId = $this->insert([
'thisTransactionOff' => 1,
'table' => 'obje !!! cts',
'data' => [
'oObject' => $data['objects']['oObject'],
'oAddress' => $data['objects']['oAddress'],
'oFloorArea' => $data['objects']['oFloorArea'],
'oWallArea' => $data['objects']['oWallArea']
]
]);
// Клиент
$personInsertId = $this->insert([
'thisTransactionOff' => 1,
'table' => 'persons',
'data' => [
'object_id' => $objectInsertId,
'pName' => $data['persons']['pName'],
'pPhone' => $data['persons']['pPhone'],
'pEmail' => $data['persons']['pEmail'],
'pSource' => $data['persons']['pSource'],
'pRegistrationDate' => $today
]
]);
// Заказ
$orderInsertId = $this->insert([
'thisTransactionOff' => 1,
'table' => 'orders',
'data' => [
'person_id' => $personInsertId,
'object_id' => $objectInsertId,
'ordRecallTime' => $data['orders']['ordRecallTime'],
'ordMeasureTime' => $data['orders']['ordMeasureTime'],
'ordRegistration' => $today,
'ordStatus' => $data['orders']['ordStatus'],
'ordCreator' => $_SESSION['user_id'],
'ordManager' => $_SESSION['user_id']
]
]);
// Запрос исполнен без очевидных ошибок, фиксируем изменения
$result = $orderInsertId;
$this->DBH->commit();
} catch (Exception $e) {
// Откатываем изменения в случае ошибки
$this->DBH->rollBack();
$result = "Заказ не был добавлен: " . $e->getMessage();
}
// Возвращаем айди нового заказа или сообщение об ошибке
return $result;
}
Содержимое метода insert
function insert(array $param)
{
// Обязательно наличие имени таблицы и данных для вставки
if (
isset($param['table'])
&& $param['table'] != ''
&& isset($param['data'])
&& !empty($param['data'])
) {
$param['ignore'] = (isset($param['ignore'])) ? 'IGNORE' : '';
// Разбираем массив для формирования prepared statement
foreach ($param['data'] as $field => $v) {
$fields[] = $field;
$values[] = ":$field";
}
$fields = implode(",", $fields);
$values = implode(",", $values);
// Формируем строку и выполняем запрос
$query = $this->DBH->prepare("INSERT {$param['ignore']} INTO {$param['table']} ($fields) VALUE ($values)");
// Если мы хотим использовать несколько вставок в рамках одной транзакции
// То отключаем транзакции у этого метода и оборачиваем несколько запросов в одну новую транзакцию
if (!isset($param['thisTransactionOff'])) {
try {
// Начинаем транзакцию
$this->DBH->beginTransaction();
// Исполняем запрос
$query->execute($param['data']);
$result = $this->DBH->lastInsertId();
// Запрос исполнен без очевидных ошибок, фиксируем изменения
$this->DBH->commit();
} catch (Exception $e) {
// Откатываем изменения в случае ошибки
$this->DBH->rollBack();
$result = "Ошибка: " . $e->getMessage();
}
} else {
try {
// Исполняем запрос
$query->execute($param['data']);
$result = $this->DBH->lastInsertId();
} catch (Exception $e) {
$result = "Ошибка: " . $e->getMessage();
}
}
} else {
$result = 'Вы не указали имя таблицы или данные для вставки';
}
// Возвращаем айди вставленной записи или сообщение об ошибке
return $result;
}