Thuta Learning
How Databases Work
ProjectsData & Databasesbeginner

ပရောဂျက် - E-Commerce Schema နှင့် Transaction Lab

ဒီခန်းပြီးရင် ဘာတတ်သွားမလဲ

  • ပရောဂျက် - E-Commerce Schema နှင့် Transaction Lab concept ကို နားလည်ရှင်းပြနိုင်ရန်
  • Diagram/table ကို ဖတ်ပြီး data model/schema/architecture ဘယ်လို ပုံသဏ္ဌာန်ရှိသလဲ ခြေရာခံနိုင်ရန်
  • ကိုယ့် project အတွက် database concept/system ကို ဘယ်လို အသုံးချသင့်သလဲ ရှင်းပြနိုင်ရန်

နားလည်ထားရမယ့် အချက်

ဒီပရောဂျက်က ယခင်သင်ခန်းစာသုံးခုကို တစ်ပြိုင်နက်တည်း ကျင့်သုံးစေသည် - schema အတွက် tables/keys/relationships; table ကြီးထွားလာသည်နှင့်အမျှ မြန်ဆန်နေအောင် indexing; multi-step write တစ်ခု လုံးဝဖြစ်ပါစေ ဒါမှမဟုတ် လုံးဝမဖြစ်ပါစေ ACID/transactions။

  • Tables, keys, relationships - schema ကိုယ်တိုင်
  • Indexing - table ကြီးလာလည်း query မြန်နေအောင်
  • Transactions & ACID - multi-step write အားလုံးဒါမှမဟုတ်တစ်ခုမှမရှိ

E-commerce ဟာ ဥပမာအစစ်ဖြစ်တယ် - 'order တင်မယ်' ခလုတ်တစ်ချက်နှိပ်ခြင်းက table များစွာကို တစ်ပြိုင်နက်ထိတွေ့ပြီး write တစ်ခုမှားရင် ငွေကြေးနှင့်ဆိုင်တဲ့ ပြဿနာဖြစ်နိုင်ပါတယ်။

Order တစ်ခုမှာ product များစွာ ပါနိုင်ပြီး product တစ်ခုကလည်း order များစွာမှာ ပါနိုင်တာကြောင့် join table Order_Items လိုအပ်ပါတယ် - ၎င်းက quantity နှင့် ဝယ်ယူချိန် price ကို ပါဆောင်ပါတယ်။

Order_Items ကို order_id နှင့် product_id နှစ်ခုလုံးဖြင့် အမြဲ query လုပ်မှာဖြစ်တာကြောင့် နှစ်ခုစလုံးအတွက် index လိုအပ်ပါတယ် - မဟုတ်ရင် table တစ်ခုလုံးကို scan လုပ်ရပါလိမ့်မယ်။

All-or-nothing

Product တစ်ခု stock ကုန်သွားရင် order အတွက် ကြိုးစားထားသမျှ write အားလုံး rollback ဖြစ်ပြီး stock count တွေ မလုပ်မီကအတိုင်း ကျန်ရှိရမည် - ဘဏ်စာရင်းလွှဲပြောင်းမှုနည်းတူ ACID guarantee ပါပဲ။

သင်ခန်းစာသုံးခုက ဘယ်လိုအထပ်ထပ်ထားလဲ - keys/relationships က table ပုံသဏ္ဍာန် ဆုံးဖြတ်ပြီး indexing က မြန်နှုန်း ဆုံးဖြတ်ပြီး ACID က ကျရှုံးမှုတွင် ဘာဖြစ်မလဲ ဆုံးဖြတ်ပါတယ်။

text
E-COMMERCE SCHEMA AND TRANSACTION FLOW
--------------------------------------
E-COMMERCE SCHEMA
-------------------------
USERS
  user_id     PK
  name

PRODUCTS
  product_id  PK
  name
  price
  stock

ORDERS
  order_id    PK
  user_id     FK -> USERS.user_id

ORDER_ITEMS
  order_item_id PK
  order_id      FK -> ORDERS.order_id
  product_id    FK -> PRODUCTS.product_id
  quantity
  price_at_purchase

RELATIONSHIPS
  USERS    1---* ORDERS
  ORDERS   1---* ORDER_ITEMS  *---1 PRODUCTS

TRANSACTION FLOW: createOrder(user, items)
-------------------------------------------
  BEGIN
    check stock for every item first
    if any item short  -> ROLLBACK (no writes)
    else:
      create ORDERS row
      create ORDER_ITEMS rows
      decrement PRODUCTS.stock
    COMMIT

လက်တွေ့ scenario နဲ့ ချိတ်ကြည့်မယ်

Schema ဒီဇိုင်းနှင့် transaction simulation နှစ်ခုလုံးကို ဒီအစီအစဉ်အတိုင်း လုပ်ဆောင်ပါ -

Users နှင့် Products ကို ဒီဇိုင်းဆွဲပါ

Table နှစ်ခုစလုံး သီးခြားရပ်တည်ပြီး တခြား table တွေ ၎င်းတို့ကို ညွှန်းသွားမည်။

Orders ထည့်ပါ

order_id PK နှင့် Users ကို ညွှန်းသော user_id FK ရှိသည်။

Order_Items ကို join table အဖြစ် ထည့်ပါ

order_id, product_id, quantity, price_at_purchase ပါဝင်သည် - price ပြောင်းလဲသည့်တိုင် history မပြောင်း။

Join table ကို index လုပ်ပါ

order_id နှင့် product_id နှစ်ခုလုံးအတွက် index ထည့်ပါ။

ဘာမှမရေးမီ stock ကို အရင်စစ်ပါ

Transaction ကို begin လုပ်ပြီး item တိုင်း stock လုံလောက်မလုံလောက် အရင်စစ်ပါ။

Commit ဒါမှမဟုတ် rollback

လုံလောက်ရင် row တွေဖန်တီးပြီး stock လျှော့ချကာ commit; မလုံလောက်ရင် write လုံးဝမလုပ်ဘဲ rollback ပြန်ပါ။

သက်သေပြပါ

Inventory တူတူကနေ အောင်မြင်တဲ့ order နှင့် fail ဖြစ်တဲ့ order နှစ်ခုလုံးကို run ပြီး stock ပြောင်းလဲမှု ကွာခြားချက်ကို ယှဉ်ကြည့်ပါ။

အတူတူ စမ်းရေးကြည့်မယ်

javascript
const products = {
  p1: { name: "Mechanical Keyboard", price: 49.99, stock: 5 },
  p2: { name: "Wireless Mouse", price: 19.99, stock: 2 }
};

const orders = [];
const orderItems = [];
let nextOrderId = 1;

function createOrder(userId, items) {
  // BEGIN TRANSACTION
  for (const item of items) {
    const product = products[item.productId];
    if (!product || product.stock < item.qty) {
      // ROLLBACK: no writes have been applied yet
      return {
        status: "ROLLBACK",
        reason: `insufficient stock for ${item.productId} (requested ${item.qty}, have ${product ? product.stock : 0})`
      };
    }
  }

  const orderId = nextOrderId++;
  const createdItems = [];
  for (const item of items) {
    products[item.productId].stock -= item.qty;
    createdItems.push({
      orderId,
      productId: item.productId,
      qty: item.qty,
      price: products[item.productId].price
    });
  }
  orders.push({ orderId, userId });
  orderItems.push(...createdItems);

  // COMMIT
  return { status: "COMMIT", orderId, items: createdItems };
}

console.log("Order 1 (sufficient stock):");
console.log(JSON.stringify(createOrder("u1", [{ productId: "p1", qty: 2 }])));
console.log("Stock after order 1:", JSON.stringify(products));

console.log("\nOrder 2 (insufficient stock):");
console.log(JSON.stringify(createOrder("u2", [{ productId: "p2", qty: 5 }])));
console.log("Stock after order 2 (unchanged):", JSON.stringify(products));
You should see
Order 1 (sufficient stock):
{"status":"COMMIT","orderId":1,"items":[{"orderId":1,"productId":"p1","qty":2,"price":49.99}]}
Stock after order 1: {"p1":{"name":"Mechanical Keyboard","price":49.99,"stock":3},"p2":{"name":"Wireless Mouse","price":19.99,"stock":2}}

Order 2 (insufficient stock):
{"status":"ROLLBACK","reason":"insufficient stock for p2 (requested 5, have 2)"}
Stock after order 2 (unchanged): {"p1":{"name":"Mechanical Keyboard","price":49.99,"stock":3},"p2":{"name":"Wireless Mouse","price":19.99,"stock":2}}

၅ မိနစ် စမ်းကြည့်

Transaction function ကို ပြင်ဆင်ပြီး quantity သည် positive integer ဖြစ်ရမည်ဆိုသည့် စစ်ဆေးမှုကို stock ထိမတိုင်မီ ထပ်ထည့်ပါ။ quantity 0 ဖြင့် test case တစ်ခု ထည့်ကာ stock မလုံလောက်ခြင်းအတွက် rollback ဖြစ်သလို quantity 0 အတွက်လည်း အလားတူ rollback ဖြစ်ကြောင်း စစ်ကြည့်ပါ။

သတိလေးတစ်ချက်

Item တိုင်း stock အရင်မစစ်ဘဲ loop ထဲမှာ item တစ်ခုစီအတွက် stock ကို တစ်ခုချင်း လျှော့ချသွားခြင်း - ဒါက product တချို့ လျှော့ချပြီး တချို့ ငြင်းပယ်ခံရနိုင်ပြီး ACID က တားဆီးလိုသည့် partial write အတိုင်းပါပဲ ဖြစ်စေနိုင်သည်

Order_Items ကို ကိုယ်ပိုင် join table အဖြစ် မဟုတ်ဘဲ Orders မှ Products သို့ တိုက်ရိုက် foreign key အဖြစ် model လုပ်ခြင်း - quantity နှင့် ဝယ်ယူချိန် price ကို line item တစ်ခုစီအလိုက် သိမ်းဆည်းနိုင်စွမ်း ဆုံးရှုံးသွားသည်

PostgreSQL Documentation: TransactionsHow Databases Work

ဒီနေရာမှာ လူအများမှားတတ်တယ်

  • Item တိုင်း stock အရင်မစစ်ဘဲ loop ထဲမှာ item တစ်ခုစီအတွက် stock ကို တစ်ခုချင်း လျှော့ချသွားခြင်း - ဒါက product တချို့ လျှော့ချပြီး တချို့ ငြင်းပယ်ခံရနိုင်ပြီး ACID က တားဆီးလိုသည့် partial write အတိုင်းပါပဲ ဖြစ်စေနိုင်သည်
  • Order_Items ကို ကိုယ်ပိုင် join table အဖြစ် မဟုတ်ဘဲ Orders မှ Products သို့ တိုက်ရိုက် foreign key အဖြစ် model လုပ်ခြင်း - quantity နှင့် ဝယ်ယူချိန် price ကို line item တစ်ခုစီအလိုက် သိမ်းဆည်းနိုင်စွမ်း ဆုံးရှုံးသွားသည်
  • ဒီ course က database concept/landscape ကို framework-neutral level မှာသာ သင်ပေးပါတယ် — SQL syntax, PostgreSQL, MongoDB, Redis ကို နက်နက်ရှိုင်းရှိုင်း လေ့လာချင်ရင် SQL, PostgreSQL, MongoDB, Redis tutorial တွေဆီ ဆက်သွားပါ။

လေ့ကျင့်ခန်း

Transaction function ကို ပြင်ဆင်ပြီး quantity သည် positive integer ဖြစ်ရမည်ဆိုသည့် စစ်ဆေးမှုကို stock ထိမတိုင်မီ ထပ်ထည့်ပါ။ quantity 0 ဖြင့် test case တစ်ခု ထည့်ကာ stock မလုံလောက်ခြင်းအတွက် rollback ဖြစ်သလို quantity 0 အတွက်လည်း အလားတူ rollback ဖြစ်ကြောင်း စစ်ကြည့်ပါ။

You'll know it worked when: Order 1 (sufficient stock): {"status":"COMMIT","orderId":1,"items":[{"orderId":1,"productId":"p1","qty":2,"price":49.99}]} Stock after order 1: {"p1":{"name":"Mechanical Keyboard","price":49.99,"stock":3},"p2":{"name":"Wireless Mouse","price":19.99,"stock":2}} Order 2 (insufficient stock): {"status":"ROLLBACK","reason":"insufficient stock for p2 (requested 5, have 2)"} Stock after order 2 (unchanged): {"p1":{"name":"Mechanical Keyboard","price":49.99,"stock":3},"p2":{"name":"Wireless Mouse","price":19.99,"stock":2}}

ပရောဂျက် - E-Commerce Schema နှင့် Transaction Lab | Thuta Learning