iT邦幫忙

1

一次上傳多筆資料 PHP PDO

如提,上網查了方式有看到
使用transaction 方式做的,還有看到準備好多筆的,想請問這兩種方式有差別嗎?
想請問如果是PDO 然後寫成第一種方式,新增筆數不固定應該如何寫呢?
第一種

INSERT INTO table_name
VALUES (value1_1, value2_2, value3_3,···),
(value2_1, value2_2, value2_3,···),
(value3_1, value3_2, value3_3,···),
······;

第二種

<?php
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "myDBPDO";

try {
  $conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
  // set the PDO error mode to exception
  $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

  // begin the transaction
  $conn->beginTransaction();
  // our SQL statements
  $conn->exec("INSERT INTO MyGuests (firstname, lastname, email)
  VALUES ('John', 'Doe', 'john@example.com')");
  $conn->exec("INSERT INTO MyGuests (firstname, lastname, email)
  VALUES ('Mary', 'Moe', 'mary@example.com')");
  $conn->exec("INSERT INTO MyGuests (firstname, lastname, email)
  VALUES ('Julie', 'Dooley', 'julie@example.com')");

  // commit the transaction
  $conn->commit();
  echo "New records created successfully";
} catch(PDOException $e) {
  // roll back the transaction if something failed
  $conn->rollback();
  echo "Error: " . $e->getMessage();
}

$conn = null;
?>

以下是小弟的程式

try{
        $conn->beginTransaction();    
        // add_room
        
        for($i=0;$i<count($_POST['data_ar']);$i++){
            $sql_add_room = "INSERT INTO 
            `tw_room_list`(`room_name`,`monthly_rental_amount`,`security_deposit_amount`,`room_floor`) 
            VALUES 
            (:house_id,:room_name,:monthly_rental_amount,:security_deposit_amount,:room_floor)";
            $result_add_room = $conn->prepare($sql_add_room);
            $status = $result_add_room->execute(array(
                ":room_name"=>"{$_POST['data_ar'][$i]['room_name']}",
                ":monthly_rental_amount"=>"{$_POST['data_ar'][$i]['monthly_rental_amount']}",
                ":security_deposit_amount"=>"{$_POST['data_ar'][$i]['security_deposit_amount']}",
                ":room_floor"=>"{$_POST['data_ar'][$i]['room_floor']}",
            ));
        }

    if($conn->commit()){
        echo 'success';
    }
        
    }catch(PDOException $e){
        $conn->rollBack();
        echo 'error';
    }
    $conn=null;
glj8989332 iT邦研究生 4 級 ‧ 2020-07-23 14:16:14 檢舉
是 [上傳] 不是 [上船]
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中
1
㊣浩瀚星空㊣
iT邦大神 1 級 ‧ 2020-07-23 17:19:42
最佳解答

兩種我都會視情況使用。

第一種在速度上會比較快且直接。
但記憶體用量會很多。效能不允許的情況下會比較容易發生問題。

一般適合少欄位資料的情況下。或是一筆資料不會超過1k容量。且不超過1000~2000筆的情況下。
我會用第一種。

第二種速度會比較慢。(慢很多)。但比較不容易去影響到業務操作。

基本上來說,需要即時性的情況下。會選擇第一種插入的方式。
如果可以後續處理的,會選用第二種方式處理。

兩者方法都各有其優缺點。沒辦法說哪一種比較好比較不好。
我是兩種都會用。

豬豬人 iT邦新手 4 級 ‧ 2020-07-24 10:24:51 檢舉

感謝,想請問,我試著用PDO去寫,但卡在execute。
我的execute()要怎麼放入呢?謝謝

$sql_add_room = "INSERT INTO 
     `tw_room_list`(`house_id`,`room_name`,`monthly_rental_amount`,`security_deposit_amount`,`room_floor`) 
     VALUES 
     (:house_id,:room_name,:monthly_rental_amount,:security_deposit_amount,:room_floor),
     (:house_id,:room_name,:monthly_rental_amount,:security_deposit_amount,:room_floor)";
     $result_add_room = $conn->prepare($sql_add_room);
     $status = $result_add_room->execute(array(':house_id' => '321',':room_name' => '2'),array(':house_id' => '321',':room_name' => '2'));
豬豬人 iT邦新手 4 級 ‧ 2020-07-24 10:29:11 檢舉

非常感謝

說真的,我會直接串字串。

但如果為了安全起見。我會程式化字串出來。

$sql_add_room = "INSERT INTO      `tw_room_list`(`house_id`,`room_name`,`monthly_rental_amount`,`security_deposit_amount`,`room_floor`) 
     VALUES ";
     $sqlAdd=[];
     $dataAdd=[];
    foreach($data AS $n=>$_d){
        $sqlAdd[] = "(:house_id_{$n},:room_name_{$n},:monthly_rental_amount_{$n},:security_deposit_amount_{$n},:room_floor_{$n})";
        $dataAdd[':house_id_'.$n] = $_d['house_id'];
        $dataAdd[':room_name_'.$n] = $_d['house_id'];
        $dataAdd[':monthly_rental_amount_'.$n] = $_d['house_id'];
        $dataAdd[':security_deposit_amount_'.$n] = $_d['house_id'];
        $dataAdd[':room_floor_'.$n] = $_d['house_id'];
    } 
    $sql_add_room .= implode(',',$sqlAdd);
     $result_add_room = $conn->prepare($sql_add_room);
     $status = $result_add_room->execute($dataAdd);

上面我只大略打一下,不確定正確性。自已研究一下。
我只是給個理念出來而已。請不要照抄

0
firecold
iT邦新手 1 級 ‧ 2020-07-23 15:20:51

簡單來說第一種在寫入的時候速度比較快(就是一次寫入多筆)
第二種比較慢因為它算是一筆一筆寫入

第一種遇到不固定筆數的寫法

//先組合data

$data = [];
foreach($data as $item){
    $data[] = "(value1, value2, value3, .... )";
}

$sql = "INSERT INTO table_name VALUES" . implode(',', $data);

大概這樣

豬豬人 iT邦新手 4 級 ‧ 2020-07-24 10:29:25 檢舉

非常感謝

2
japhenchen
iT邦超人 1 級 ‧ 2020-07-23 16:10:30

應該這樣講,一筆一筆insert的,你在無法保証工作是否會因為網路或電腦不穩定而中斷的情況下,是非常冒險的一件事,你的交易如果有10000行,你執行到100行時電腦當掉,你能忍受只有存進了99筆?還是一定要保証10000筆都完成才可以?真的要缺一不可,那你就得做
start transaction ;
....
commit ;

雖然說現在的電腦、網路都已不是吳下阿蒙,但~~意外總是會在意想不到的時候出現

豬豬人 iT邦新手 4 級 ‧ 2020-07-24 10:29:37 檢舉

非常感謝

0
淺水員
iT邦大師 6 級 ‧ 2020-07-23 16:48:12

兩種都是全寫入或是全不寫入。
第一種算是只下一次命令,第二種是分好幾次下。
但是第一種如果是自己接字串的話,可能要做好過濾,不然會有注入的風險。
第二種則是要注意效能的問題,也有可能會出現 deadlock(死鎖 OR 死結) 的狀況。

PS. 第一種配合 prepare 的方式研究中...

淺水員 iT邦大師 6 級 ‧ 2020-07-23 17:43:54 檢舉

關於程式的部分:

  1. for($i=0;$i<count($_POST['data_ar']);$i++){ 這邊建議把count($_POST['data_ar']) 先用變數暫存起來,才不用迴圈每跑一次都要呼叫 count 函式。
  2. 推薦一下 bindParam 的用法,可以類似這樣。
try{
    $conn=new PDO('...略');
    $sql = 'INSERT INTO `test`(
        `name`,
        `price`
    ) VALUES (
        :name,
        :price
    )';
    $stmt = $conn->prepare($sql);
    $stmt->bindParam(':name', $name, PDO::PARAM_STR);
    $stmt->bindParam(':price', $price, PDO::PARAM_INT);
    foreach($datas as $row){
        $name=$row['name'];
        $price=$row['price'];
        if($stmt->execute()===false) {
            throw new Exception('error');
        }
    }
    echo 'success';
}catch(PDOException $e){
    echo $e;
}
豬豬人 iT邦新手 4 級 ‧ 2020-07-24 10:29:44 檢舉

非常感謝

0
ckp6250
iT邦好手 1 級 ‧ 2020-07-23 17:02:29

把資料先弄成 json 格式,
然後在 stored procedure 中去解析 json
組成 prepare
接著套用
start transaction ;
....
commit ;

我要發表回答

立即登入回答