Как лучше всего вставлять записи Master/Detail с помощью PHP-MySQL

У меня есть таблица «Мастер заказа на продажу» (so_mstr) и дочерняя таблица «Сведения о заказе на продажу» (sod_det). Я получаю подробные записи из массива $_POST[] и готовлю основную запись внутри самого скрипта. Ожидается, что мой сценарий будет работать следующим образом.

  1. Вставить основную запись.
  2. Вставьте подробные записи с помощью PHP for loop (запрос для каждой подробной записи).
  3. Обновите другую таблицу после успешного выполнения шагов 1 и 2.

В случае сбоя любого из шагов следует выполнить откат всего процесса.

Я пробовал следующий код до сих пор. Он продолжает вставлять подробные записи даже в случае сбоя основного запроса на вставку. Любая идея, как убедиться, что все запросы выполняются успешно или полностью откатываются, если какой-либо из них не работает?

mysqli_autocommit($conn, FALSE);
mysqli_begin_transaction();

$insert_mstr = 'insert into so_mstr(...) values(...)';
mysqli_query($conn, $insert_mstr);

foreach ($order_details['order_details'] as $line_item) {
    $insert_line = 'INSERT INTO sod_det(...) values(...)';
    mysqli_query($conn, $insert_line);
}

if(mysqli_commit($conn)){
    insert_ar_reco(); // inserts into another table
    increment_soseq($conn, $param); // updates a table
}
else{
    echo 'Error occurred! transaction rolled back.';
}

person Aditya Amit    schedule 10.09.2018    source источник


Ответы (2)


Вы можете использовать приведенный ниже способ использования функций отката и фиксации.

mysqli_query($con, "SET AUTOCOMMIT=0");
mysqli_query($con,"START TRANSACTION");
$insertMain = mysqli_query($con,''); // Insert query for Sales Order Master (so_mstr) table
foreach(($order_details['order_details'] as $line_item) {
   $insertChild = mysqli_query($con,''); // Insert query for Sales Order Details (sod_det) table
   if(!$insertChild){
       break;
   }
}

if($insert1 && $insert2) {
    mysqli_query($con,"COMMIT");
} else {
    mysqli_query($con,"ROLLBACK");
}
mysqli_query($con, "SET AUTOCOMMIT=1");

обновление: если вы используете mysqli объектно-ориентированным способом, вы можете сделать следующее:

$mysqli->begin_transaction();
$insertMain = $mysqli->query(''); // Insert query for Sales Order Master (so_mstr) table
foreach(($order_details['order_details'] as $line_item) {
   $insertChild = $mysqli->query(''); // Insert query for Sales Order Details (sod_det) table
   if(!$insertChild){
       break;
   }
}

if($insert1 && $insert2) {
    $mysqli->commit();
} else {
    $mysqli->rollback();
}

СОВЕТ: если вы используете более старую версию PHP 5.5.0, вы не можете использовать $mysqli->begin_transaction(); и вместо этого должны использовать $mysqli->autocommit(false); в начале и $mysqli->autocommit(true); в конце.

person Bhavin Solanki    schedule 10.09.2018
comment
Супер класс! Работал как шарм! Большое спасибо @Bhavin - person Aditya Amit; 10.09.2018

Используйте «пакетную вставку» вместе с «фиксацией» и «откатом»

person AGK    schedule 10.09.2018