0Pricing
Go Academy · บทเรียน

ธุรกรรม

ยืนยันหรือย้อนกลับธุรกรรม

ธุรกรรม เป็นบทเรียน Go Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Go Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Go Academy มีบทเรียนทั้งหมด 4 บทเรียน

เหตุผลที่ต้องใช้ธุรกรรม

ธุรกรรม จัดกลุ่มคำสั่งหลายรายการไว้ด้วยกัน เพื่อให้ทั้งหมดสำเร็จหรือทั้งหมดล้มเหลวไปพร้อมกัน วิธีนี้ช่วยให้ข้อมูลสอดคล้องกัน เช่น การโอนเงินระหว่างบัญชีสองบัญชีโดยไม่ทำให้เงินสูญหายระหว่างทาง

  • เป็นอะตอม: ทำทั้งหมดหรือไม่ทำเลย
  • สถานะสอดคล้องกัน
  • แยกจากธุรกรรมอื่น

การเริ่มธุรกรรมด้วย Begin

Begin เริ่มธุรกรรมและส่งคืนค่า *sql.Tx คุณเรียกใช้คำสั่งบน Tx ไม่ใช่บนกลุ่มการเชื่อมต่อ เพื่อให้คำสั่งเหล่านั้นใช้การเชื่อมต่อเดียวและธุรกรรมเดียวกัน

tx, err := db.Begin()
if err != nil {
    log.Fatal(err)
}

คำสั่งบน Tx

เรียกใช้ tx.Exec และ tx.Query ได้เช่นเดียวกับการเรียกใช้บนฐานข้อมูล แต่ทุกอย่างจะทำงานภายในธุรกรรมจนกว่าจะยืนยันหรือย้อนกลับธุรกรรม

_, err = tx.Exec("UPDATE accounts SET balance = balance - $1 WHERE id = $2", 100, 1)

ยืนยันธุรกรรม

tx.Commit() ทำให้การเปลี่ยนแปลงทั้งหมดมีผลถาวรและผู้อื่นมองเห็นได้ หากส่งคืนข้อผิดพลาด แสดงว่าธุรกรรมนั้นยังไม่ถูกนำไปใช้

if err := tx.Commit(); err != nil {
    log.Fatal(err)
}

ย้อนกลับธุรกรรม

หากขั้นตอนใดล้มเหลว ให้เรียก tx.Rollback() เพื่อยกเลิกการเปลี่ยนแปลงทั้งหมดนับตั้งแต่ Begin ฐานข้อมูลจะกลับสู่สถานะเดิมราวกับว่าไม่มีอะไรเกิดขึ้น

if err != nil {
    tx.Rollback()
    return err
}

รูปแบบ defer Rollback

รูปแบบการเขียนที่รัดกุมคือเลื่อนการทำงานของ Rollback ไว้ทันทีหลังจาก Begin การเรียก Rollback หลังจากยืนยันธุรกรรมสำเร็จแล้วจะไม่ทำอะไรและไม่ก่อผลเสีย ดังนั้นรูปแบบนี้จึงรับประกันการคืนทรัพยากรในทุกเส้นทางที่เกิดข้อผิดพลาด

tx, err := db.Begin()
if err != nil { return err }
defer tx.Rollback()
// ... do work ...
return tx.Commit()

ตัวอย่างการโอนแบบอะตอม

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

การจำลองธุรกรรมที่เรียกใช้งานได้

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

package main

import (
    "errors"
    "fmt"
)

func transfer(bal map[string]int, from, to string, amt int) error {
    if bal[from] < amt {
        return errors.New("insufficient funds")
    }
    snapshot := map[string]int{from: bal[from], to: bal[to]}
    bal[from] -= amt
    bal[to] += amt
    if bal[from] < 0 {
        bal[from], bal[to] = snapshot[from], snapshot[to]
        return errors.New("rolled back")
    }
    return nil
}

func main() {
    bal := map[string]int{"alice": 100, "bob": 20}
    if err := transfer(bal, "alice", "bob", 30); err != nil {
        fmt.Println("error:", err)
    } else {
        fmt.Println("committed:", bal)
    }
}

ระดับการแยกธุรกรรม

db.BeginTx รับตัวเลือกต่าง ๆ รวมถึงระดับการแยกธุรกรรม เช่น sql.LevelSerializable ระดับการแยกที่สูงขึ้นช่วยป้องกันความผิดปกติได้มากขึ้น แต่อาจลดการทำงานพร้อมกัน

tx, err := db.BeginTx(ctx, &sql.TxOptions{Isolation: sql.LevelSerializable})

ทำธุรกรรมให้สั้น

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

ห้ามใช้ db และ tx ปะปนกัน

ภายในธุรกรรม ให้เรียกใช้คำสั่งบน tx เท่านั้น การเรียก db.Exec ที่จุดนั้นจะใช้การเชื่อมต่ออื่นนอกธุรกรรม ดังนั้นการเปลี่ยนแปลงดังกล่าวจึงไม่เป็นส่วนหนึ่งของธุรกรรมและจะไม่ถูกย้อนกลับ

ตรวจสอบความเข้าใจอย่างรวดเร็ว

ทดสอบความรู้เกี่ยวกับธุรกรรม

สรุปทบทวน

คุณได้เรียนรู้เกี่ยวกับธุรกรรมดังนี้:

  • Begin ส่งคืน *sql.Tx และให้เรียกใช้คำสั่งบนค่านั้น
  • Commit ทำให้การเปลี่ยนแปลงคงอยู่ ส่วน Rollback ยกเลิกการเปลี่ยนแปลงทั้งหมด
  • defer tx.Rollback() รับประกันการคืนทรัพยากรเมื่อเกิดข้อผิดพลาด
  • BeginTx กำหนดการแยกธุรกรรม และควรทำธุรกรรมให้สั้น
  • ห้ามใช้ db และ tx ปะปนกันภายในธุรกรรมเดียว

คำถามที่พบบ่อย

บทเรียน “ธุรกรรม” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “ธุรกรรม” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Go Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Go Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “ธุรกรรม”

ยืนยันหรือย้อนกลับธุรกรรม คุณปฏิบัติ Go Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Go Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Go Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน

บทเรียน “ธุรกรรม” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Go Academy นี้ได้ไหม

ได้ บทเรียน Go Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การเปิดการเชื่อมต่อ
  2. การสอบถามแถวข้อมูล
  3. คำสั่งที่เตรียมไว้
  4. ธุรกรรม
← กลับไปที่ Go Academy