본문으로 건너뛰기

เนื้อหาภาษาไทย / 태국어 콘텐츠

시스템 가이드 검수 완료된 콘텐츠

การจัดการ Transaction ด้วย PDO

การจัดการ Transaction ด้วย PDO

ในบทเรียนก่อนหน้านี้ เราได้เรียนรู้เกี่ยวกับการสร้าง, อ่าน, แก้ไข, และลบข้อมูล (CRUD Operations) โดยใช้ PDO (PHP Data Objects) ในบทนี้ เราจะมาเรียนรู้เกี่ยวกับการจัดการ Transaction ซึ่งเป็นเครื่องมือสำคัญในการรักษาความถูกต้องของข้อมูลเมื่อมีการดำเนินการหลายอย่างที่เกี่ยวข้องกันในฐานข้อมูล

Transaction คืออะไร?

Transaction คือลำดับของการดำเนินการ (operations) ที่ถือว่าเป็นหน่วยการทำงานเดียว (atomic unit) ซึ่งหมายความว่าการดำเนินการทั้งหมดใน Transaction จะต้องสำเร็จ (commit) หรือล้มเหลวทั้งหมด (rollback) หากมีส่วนใดส่วนหนึ่งของ Transaction ล้มเหลว การเปลี่ยนแปลงทั้งหมดที่เกิดขึ้นก่อนหน้านั้นจะถูกยกเลิก เพื่อให้ฐานข้อมูลกลับสู่สถานะเดิมก่อนที่จะเริ่ม Transaction

ลองนึกภาพว่าคุณกำลังโอนเงินจากบัญชีหนึ่งไปยังอีกบัญชีหนึ่ง การโอนเงินนี้ประกอบด้วยสองขั้นตอน:

  1. ลดจำนวนเงินในบัญชีต้นทาง
  2. เพิ่มจำนวนเงินในบัญชีปลายทาง

หากขั้นตอนแรกล้มเหลว (เช่น บัญชีต้นทางมีเงินไม่พอ) แต่ขั้นตอนที่สองสำเร็จ เงินก็จะหายไปจากระบบ! Transaction ช่วยป้องกันปัญหานี้ได้ โดยถ้าขั้นตอนแรกล้มเหลว ขั้นตอนที่สองจะไม่ถูกดำเนินการ และบัญชีทั้งสองจะอยู่ในสถานะเดิม

ทำไมต้องใช้ Transaction?

Transaction มีประโยชน์อย่างมากในการรักษาความสอดคล้องของข้อมูล (data consistency) ในสถานการณ์ที่ซับซ้อน ซึ่งเกี่ยวข้องกับการดำเนินการหลายอย่างที่ต้องเกิดขึ้นพร้อมกันหรือไม่มีเลย ตัวอย่างเช่น:

  • การโอนเงินระหว่างบัญชี (ดังที่กล่าวมา)
  • การสั่งซื้อสินค้าออนไลน์ (ต้องบันทึกข้อมูลการสั่งซื้อ, ลดจำนวนสินค้าคงคลัง, และบันทึกการชำระเงิน)
  • การลงทะเบียนผู้ใช้ (ต้องบันทึกข้อมูลผู้ใช้, สร้างบัญชี, และส่งอีเมลยืนยัน)

หากไม่มี Transaction และเกิดข้อผิดพลาดระหว่างการดำเนินการ อาจทำให้ข้อมูลในฐานข้อมูลไม่ถูกต้องหรือไม่สมบูรณ์

การเริ่มต้น Transaction

ในการเริ่มต้น Transaction ด้วย PDO เราจะใช้เมธอด beginTransaction() ของอ็อบเจ็กต์ PDO:

try {
    // สร้างการเชื่อมต่อ PDO (สมมติว่า $pdo ถูกสร้างไว้แล้ว)

    // เริ่มต้น Transaction
    $pdo->beginTransaction();

    // ดำเนินการ SQL queries ที่เกี่ยวข้องกับ Transaction
    // ...

} catch (PDOException $e) {
    // เกิดข้อผิดพลาด
    // ...
}

โค้ดนี้จะเริ่มต้น Transaction บนการเชื่อมต่อฐานข้อมูลที่ระบุ เมื่อ Transaction เริ่มต้นแล้ว การเปลี่ยนแปลงใดๆ ที่เกิดขึ้นกับฐานข้อมูลจะไม่ถูกบันทึกถาวร จนกว่าเราจะ commit Transaction

การ Commit Transaction

หากการดำเนินการทั้งหมดใน Transaction สำเร็จ เราจะบันทึกการเปลี่ยนแปลงทั้งหมดลงในฐานข้อมูลอย่างถาวร โดยใช้เมธอด commit():

try {
    // สร้างการเชื่อมต่อ PDO (สมมติว่า $pdo ถูกสร้างไว้แล้ว)

    // เริ่มต้น Transaction
    $pdo->beginTransaction();

    // ดำเนินการ SQL queries ที่เกี่ยวข้องกับ Transaction
    $stmt1 = $pdo->prepare("UPDATE accounts SET balance = balance - :amount WHERE account_id = :account_from");
    $stmt1->bindParam(':amount', $amount, PDO::PARAM_INT);
    $stmt1->bindParam(':account_from', $accountFrom, PDO::PARAM_INT);
    $stmt1->execute();

    $stmt2 = $pdo->prepare("UPDATE accounts SET balance = balance + :amount WHERE account_id = :account_to");
    $stmt2->bindParam(':amount', $amount, PDO::PARAM_INT);
    $stmt2->bindParam(':account_to', $accountTo, PDO::PARAM_INT);
    $stmt2->execute();


    // Commit Transaction
    $pdo->commit();

    echo "Transaction สำเร็จ!";

} catch (PDOException $e) {
    // เกิดข้อผิดพลาด
    // ...
}

หาก commit() สำเร็จ การเปลี่ยนแปลงทั้งหมดที่เกิดขึ้นระหว่าง beginTransaction() และ commit() จะถูกบันทึกถาวรในฐานข้อมูล

การ Rollback Transaction

หากมีการดำเนินการใดๆ ใน Transaction ล้มเหลว เราจะยกเลิกการเปลี่ยนแปลงทั้งหมดที่เกิดขึ้นก่อนหน้านี้ โดยใช้เมธอด rollback():

try {
    // สร้างการเชื่อมต่อ PDO (สมมติว่า $pdo ถูกสร้างไว้แล้ว)

    // เริ่มต้น Transaction
    $pdo->beginTransaction();

    // ดำเนินการ SQL queries ที่เกี่ยวข้องกับ Transaction
    $stmt1 = $pdo->prepare("UPDATE accounts SET balance = balance - :amount WHERE account_id = :account_from");
    $stmt1->bindParam(':amount', $amount, PDO::PARAM_INT);
    $stmt1->bindParam(':account_from', $accountFrom, PDO::PARAM_INT);
    $stmt1->execute();

    //จำลองการเกิดข้อผิดพลาด
    if($amount > 10000){
        throw new Exception("จำนวนเงินมากเกินไป");
    }

    $stmt2 = $pdo->prepare("UPDATE accounts SET balance = balance + :amount WHERE account_id = :account_to");
    $stmt2->bindParam(':amount', $amount, PDO::PARAM_INT);
    $stmt2->bindParam(':account_to', $accountTo, PDO::PARAM_INT);
    $stmt2->execute();


    // Commit Transaction
    $pdo->commit();

    echo "Transaction สำเร็จ!";

} catch (PDOException | Exception $e) {
    // เกิดข้อผิดพลาด
    echo "Transaction ล้มเหลว: " . $e->getMessage();

    // Rollback Transaction
    $pdo->rollBack();
}

หาก rollback() ถูกเรียกใช้ การเปลี่ยนแปลงทั้งหมดที่เกิดขึ้นระหว่าง beginTransaction() และ rollback() จะถูกยกเลิก และฐานข้อมูลจะกลับสู่สถานะเดิมก่อนที่จะเริ่ม Transaction

ตัวอย่างการใช้งาน Transaction

ต่อไปนี้เป็นตัวอย่างที่สมบูรณ์ของการใช้ Transaction ในการโอนเงินระหว่างบัญชี:

<?php

// ข้อมูลการเชื่อมต่อฐานข้อมูล
$host = 'localhost';
$db   = 'testdb';
$user = 'root';
$pass = '';
$charset = 'utf8mb4';

$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$options = [
    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    PDO::ATTR_EMULATE_PREPARES   => false,
];

try {
    $pdo = new PDO($dsn, $user, $pass, $options);

    $accountFrom = 1; // รหัสบัญชีต้นทาง
    $accountTo = 2;   // รหัสบัญชีปลายทาง
    $amount = 500;    // จำนวนเงินที่ต้องการโอน

    // เริ่มต้น Transaction
    $pdo->beginTransaction();

    // ลดจำนวนเงินในบัญชีต้นทาง
    $stmt1 = $pdo->prepare("UPDATE accounts SET balance = balance - :amount WHERE account_id = :account_from");
    $stmt1->bindParam(':amount', $amount, PDO::PARAM_INT);
    $stmt1->bindParam(':account_from', $accountFrom, PDO::PARAM_INT);
    $stmt1->execute();

    // เพิ่มจำนวนเงินในบัญชีปลายทาง
    $stmt2 = $pdo->prepare("UPDATE accounts SET balance = balance + :amount WHERE account_id = :account_to");
    $stmt2->bindParam(':amount', $amount, PDO::PARAM_INT);
    $stmt2->bindParam(':account_to', $accountTo, PDO::PARAM_INT);
    $stmt2->execute();

    // Commit Transaction
    $pdo->commit();

    echo "Transaction สำเร็จ! โอนเงิน $amount จากบัญชี $accountFrom ไปยังบัญชี $accountTo";

} catch (PDOException $e) {
    // เกิดข้อผิดพลาด
    echo "Transaction ล้มเหลว: " . $e->getMessage();

    // Rollback Transaction
    $pdo->rollBack();
}

?>

ในตัวอย่างนี้ หากการลดจำนวนเงินในบัญชีต้นทางสำเร็จ แต่การเพิ่มจำนวนเงินในบัญชีปลายทางล้มเหลว (เช่น บัญชีปลายทางไม่มีอยู่) Transaction จะถูก rollback และการเปลี่ยนแปลงทั้งหมดจะถูกยกเลิก

สรุป

Transaction เป็นเครื่องมือที่มีประสิทธิภาพในการรักษาความถูกต้องของข้อมูลในฐานข้อมูล การใช้ Transaction ช่วยให้เราสามารถดำเนินการหลายอย่างที่เกี่ยวข้องกันได้อย่างปลอดภัย และมั่นใจได้ว่าข้อมูลในฐานข้อมูลจะสอดคล้องกันเสมอ ในบทเรียนถัดไป เราจะเรียนรู้เกี่ยวกับการตรวจสอบ (validation) ข้อมูลที่รับมาจากผู้ใช้ ก่อนที่จะนำไปบันทึกในฐานข้อมูล เพื่อป้องกันปัญหาต่างๆ ที่อาจเกิดขึ้น

Office.in.th Custom Service

이 구조를 바탕으로 시스템을 개발하거나 맞춤 변경하고 싶으신가요?

Office.in.th는 엔터프라이즈 웹 애플리케이션, API 연동, 공공/민간 업무 관리 시스템을 설계·개발하며 장기 지원을 제공합니다.

소프트웨어 개발 서비스 보기