Database Transaction and Isolation level

Banana boy~~
ChomCHOB
2 min readSep 28, 2023

--

ก่อนที่เราจะไปเริ่มกับหัวข้อ Database transaction ผมอยากจะปูเรื่อง Database คร่าวๆ กันก่อนเพื่อที่ให้ได้เข้าใจตรงกัน งั้นเรามาเริ่มกัน

Database คืออะไร

Database หรือฐานข้อมูล คือสิ่งที่ใช้เก็บข้อมูลต่างๆ ตรงตัวมันเลยโดยจะมี Software เข้ามาควบคุมเรื่องการจัดการ การจัดเก็บข้อมูลในรูปแบบ Digital หรือข้อมูลเชิงตรรกะต่างๆ เพื่อรอการเรียกข้อมูลนั่นเอาไปประมวลผลหรือคำนวนต่อไป

Database นั้นก็แบ่งได้เป็นหลักๆ คือ SQL กับ NoSQL ซึ่งในที่นี้เราจะพูดถึงแค่ SQL ที่เป็นส่วนสำคัญของบทความนี้

แล้ว SQL คืออะไร?

Structured Query Language (SQL) เป็นภาษาโปรแกรมสำหรับจัดเก็บและประมวลผลข้อมูลในฐานข้อมูลแบบเชิงสัมพันธ์ ฐานข้อมูลแบบเชิงสัมพันธ์เก็บข้อมูลในรูปแบบตารางที่มีแถวและคอลัมน์ที่เป็นตัวแทนของหมวดข้อมูลที่แตกต่างกันและความสัมพันธ์ต่างๆ ระหว่างค่าข้อมูล สามารถใช้คำสั่ง SQL ในการจัดเก็บ ปรับปรุง ลบ ค้นหา และดึงข้อมูลจากฐานข้อมูล นอกจากนี้ยังสามารถใช้ SQL ในการรักษาและเพิ่มประสิทธิภาพการทำงานของฐานข้อมูล

การจะเรียกใช้ดูข้อมูลต่างๆ ของ SQL ได้จำเป็นต้องมีสิ่งที่เรียกว่า SQL Statement ซึ่งหลักๆ จะได้แก่ INSERT, UPDATE, DELETE, SELECT ทั้งหมดนี้คำสั่งการใช้งาน SQL ไม่ว่าเรียกมาดู สร้าง อัพเดท และลบตรงตัวกับชื่อคำสั่ง (ถ้าตรงนี้สงสัยผู้อ่านสามารถหาอ่านได้ในบทความหรือหนังสือต่างๆ ได้เลยนะครับ)

ที่นี้เราจะมาพูดถึงว่าทำไมเราถึงต้องเราต้องมี Database transaction และ Database Transaction มันคืออะไร

ทำไมเราถึงต้องเราต้องมี Database Transaction

ผมอยากจะยกตัวอย่างความผิดพลาดของระบบสักนิดนึงเพื่อที่ให้เข้าใจได้ง่าย เช่นมีการเรียก service เพื่อให้ระบบทำการสร้าง data ลงไปใน database จากนั้นระบบต้องส่งข้อมูลไปหา service อื่นที่อยู่คนละที่กันแต่ บังเอิญ!! service ที่เรียกไปดันล่มขึ้นมาและ service ต้องการที่จะส่ง error กลับไปหาที่คนที่เรียกมา แต่ถ้าดูดีๆ มันเกิดการสร้างข้อมูลขึ้นมาแล้ว ทำให้มันค้าง data ในระบบที่พึ่งสร้างไป ดังนั้นเราอาจต้องทำการ delete ข้อมูลนั้นทิ้งไปซึ่งมันก็ไม่ใช่วิธีที่ดีเท่าไหร่ ดังนั้นจากปัญหาที่ได้ยกตัวอย่างมานั้นทำให้เกิดสิ่งที่เรียกว่า Transaction ขึ้นมาเพื่อแก้และจัดการกับปัญหาเหล่านั้น

⚠️ หมายเหตุ ตัวอย่างที่ได้ยกมานั้นเป็นแค่ส่วนเล็กน้อยเท่านั้นเมื่อเทียบกับปัญหาที่ได้เจอกันในการทำงานจริง แนะนำให้ผู้อ่านหาพวกตัวอย่างจากในบทความอื่นๆ เพื่อศึกษา Case by Case กันต่อไป

Database Transaction มันคืออะไร

Database Transaction หรือ Transaction คือคำสั่ง SQL ที่มีหน้าที่กำกับดูแลการทำงานของ SQL Statement ทั้งหมดของคำสั่งที่ถูกป้อนเข้ามา หรือชุดคำสั่ง SQL หลายๆ คำสั่งที่ต้องการจะติดตามและนำทั้งหมดนั้นมาจัดการต่อไป ซึ่งจะมีอยู่ 2 State ให้เลือกคือ COMMIT และ ROLLBACK เช่นถ้าระบบทำงานปกติทำงานจนจบได้จึงสั่ง COMMIT เพื่อทำการสั่งยอมรับการทำการทั้งหมดใน transaction นั่น แต่ถ้าเกิดข้อผิดพลาดขึ้นจาก sequence ที่อยู่ใน transaction นั่นๆ ก็สามารถสั่ง Rollback เพื่อทำการคืนค่าข้อมูลทั้งหมดที่ทำไปใน transaction นั้นได้ทันทีโดยไม่เกิดผลกระทบกับฐานข้อมูลเลย อีกทั้งยังมีการ SAVE POINT เพื่อเป็นจุดที่สามารถกลับมาได้เมื่อเกิดข้อผิดพลาดขึ้นที่ไม่จำเป็นต้อง ROLLBACK ทั้งหมดทิ้งไป

ซึ่งการทำงานหลักของ Transaction ต้องอยู่ในเงื่อนไขและคุณสมบัติ ACID

ACID คืออะไร

  • Atomicity − คือการที่แต่ละ transaction ต้อง “all or nothing” หมายถึง ถ้ามีกระบวนการใดหรือส่วนหนึ่งส่วนใด fail ทั้งหมดของ transaction นั้นมีค่าเป็น fail และ database จะยกเลิกการเปลี่ยนแปลงที่เกิดจาก transaction นั้น
  • Consistency − คือคุณสมบัตที่จะต้องแน่ใจได้ว่า ไม่ว่า transaction จะทำถึงกระบวนการไหนข้อมูลจะต้องถูกเขียนลงบน database อย่างถูกต้องตามกฎที่ตั้งไว้
  • Isolation − คือคุณสมบัติที่จะมั่นใจว่า ทุกๆผลลัพธ์จากการทำงานของ transaction จะถูกต้องต่อให้กระบวนการของ transaction ก่อนจะไม่สมบูรณ์ก็จะไม่มีผลกระทบต่อ transaction อื่น
  • Durability − คือ คุณสมบัติที่เมื่อใดก็ตามที่ transaction มีการ “committed” ข้อมูล transaction นั้นจะต้องยังคงอยู่ครบถ้วน ถึงแม้จะเกิดไฟดับ หรือ ระบบล่มหลังจากนั้น

ผมจะยกตัวอย่างการใช้งานใน SQL สักนิดนึง

START TRANSACTION;
INSERT INTO users (user_name, email) VALUES('yunyong1','yunyong1@email.com');
INSERT INTO users (user_name, email) VALUES('yunyong2','yunyong2@email.com');
COMMIT;

ในตัวอย่างนี้การไปสร้าง transaction ขึ้นมาแล้ว INSERT user ลงไป 2 rows แล้วจึงทำการ COMMIT แล้วถ้าอยากจะ ROLLBACK หล่ะจะทำยังไงก็แค่เปลี่ยนจาก COMMIT เป็น ROLLBACK ก็จะกลายเป็นการย้อน transaction แล้วดังนี้

START TRANSACTION;
INSERT INTO users (user_name, email) VALUES('yunyong1','yunyong1@email.com');
INSERT INTO users (user_name, email) VALUES('yunyong2','yunyong2@email.com');
ROLLBACK;

ตัวอย่างคร่าวๆ ก็จะมีประมาณนี้ ทีนี้ก็จะมีการเข้าถึงของ Transaction อีกที่จะมีปัญหาเรื่อง Concurrency ที่ไม่สามารถทำงานพร้อมกันแล้วให้ผลลัพธ์ออกมาถูกได้ดังนั้นก็จะมีสิ่งที่เรียกว่า Isolation level เข้ามากำกับอีกว่า transaction นั้นสามารถทำอะไรได้บ้างในระหว่างที่อีก transaction นึงกำลังทำงานใน data row เดียวกัน

Isolation level คืออะไร

Isolation level คือ property ที่ใช้กำหนดว่าจะให้ transaction อื่นๆ ที่ทำงานในเวลาเดียวกันมองเห็นการเปลี่ยนแปลงในฐานข้อมูลที่เกิดจาก transaction ของเราได้ยังไงต้องตรวจสอบการ LOCK ของ row นั้นก่อนหรือไม่ และเมื่อไหร่ (เห็นตอนแก้ไข หรือเห็นตอนเสร็จแล้ว) โดยที่จะแบ่งได้เป็น 4 ระดับได้แก่

  1. Read Uncommitted เป็น Isolation Level ระดับต่ำที่สุด ซึ่งมีการทำงานใช้ข้อมูลร่วมกัน โดยไม่มีการ Lock ข้อมูลเลย อีกทั้งยังสามารถนำข้อมูลผลลัพธ์ของ Transaction ที่ยังไม่ Commit ไปใช้งานได้อีกด้วย จึงทำให้อัตราความผิดพลาดของข้อมูลในฐานข้อมูลมีโอกาสเกิดได้สูง กล่าวได้ว่า Isolation Level ระดับนี้ ไม่ได้แก้ปัญหา Concurrency Control Problem ข้อใด ๆ ได้เลย ซึ่งมักจะกำหนด Isolation Level นี้กับงานที่ให้บริการอ่านข้อมูลได้อย่างเดียว ไม่สามารถเพิ่ม ลบ และแก้ไขข้อมูลได้ หรือไม่มีการแก้ไขข้อมูลบ่อยนัก ซึ่งจะสามารถรองรับผู้ใช้งานพร้อมกันในเวลาเดียวกันได้เป็นจำนวนมาก
  2. Read Committed หรือ Cursor Stability เป็น Isolation Level มีการทำงานที่การใช้งานข้อมูลนั้นจะต้องเป็นข้อมูลผลลัพธ์ของ Transaction ที่ Commit แล้วเท่านั้น กล่าวคือหากอยู่ในระหว่างการทำงานของ Transaction ข้อมูลนั้นจะยังไม่สามารถใช้งานได้จนกว่า Transaction นั้นจะ Commit เสียก่อน เป็นการแก้ กล่าวได้ว่า Isolation Level นี้สามารถแก้ได้เท่านั้น ส่วนปัญหาข้ออื่นไม่สามารถแก้ปัญหาได้ Isolation Level นี้มักจะใช้ในงานที่ให้บริการข้อมูลผ่าน Web Application ที่มีการแก้ไข — เพิ่มข้อมูลได้ซึ่งต้องการเพียงแสดงข้อมูลที่ถูกต้อง (Commit แล้ว) และรองรับผู้ใช้งานจำนวนมากเท่านั้น
  3. Repeatable Read มีลักษณะการทำงานอยู่ในรูปแบบ HOLD LOCK ระหว่างที่กำลังทำงานกับข้อมูลจะไม่ปลด Lock จนกว่า Transaction จะ Commit ซึ่งจะแก้ได้
  4. Serializable เป็น Isolation Level ระดับสูงสุดที่สามารถแก้ปัญหา Concurrency Control Problem ซึ่งรับประกันถึงความถูกต้องของข้อมูลสูงสุดด้วย แต่ว่า Isolation Level นี้มีอัตราการ Lock ข้อมูลสูงและมีโอกาสของการเกิด Deadlock สูงด้วย

แล้วจะใช้ยังไงละจริงๆ เวลาจะใช้งาน transaction นั้นต้องมีการ SET ISOLATION LEVEL ก่อนที่จะทำการ START TRANSACTION ซึ่งมันจะกำหนดเป็นแบบ Global ซึ่งกำหนดแค่ครั้งเดียวแล้วใช้ได้ตลอด

สรุปช่วงท้ายแล้วว

จากบทความนี้จะเห็นได้ว่าการที่รันคำสั่ง SQL ไปเรื่อยๆ มันมีโอกาสที่จะเกิดข้อผิดพลาดเกี่ยวกับการทำงานของมันได้จึงจำเป็นต้องมี transaction และระดับการเข้าถึงมาช่วยกำกับเพื่อให้ข้อมูลเป็นไปอย่างถูกต้อง

จริงๆ แล้วยังมีปัญหาเรื่อง Concurrency Control Problem อีกที่ไม่ได้พูดถึงซึ่งเป็นเหตุผลหลักเลยที่ต้องเลือกใช้ transaction และ isolation level ให้เหมาะสมแต่ผู้อ่านสามารถไปหาอ่านเพิ่มเติมได้ตามหนังสือและแหล่งบทความต่างๆ

ก็หวังว่าจะเป็นประโยชน์กับ Developer ที่อยากเรียนรู้เพิ่มเติม และอยากให้มีไฟในการเรียนรู้ต่อไปเรื่อยๆ อย่าได้หยุดพัฒนาตัวเองสู้ๆ ต่อไปยังมีอีกเยอะที่ต้องรู้ ✌️

สุดท้ายนี้ก็ขอบคุณที่อ่านจนจบครับ 🙏

--

--