paint-brush
ازگر: جینگو ٹرانزیکشنز کیسے کام کرتی ہیں اس پر گہری نظرکی طرف سے@mta
134 ریڈنگز نئی تاریخ

ازگر: جینگو ٹرانزیکشنز کیسے کام کرتی ہیں اس پر گہری نظر

کی طرف سے Michael T. Andemeskel9m2025/03/02
Read on Terminal Reader

بہت لمبا؛ پڑھنے کے لئے

Django's transaction.atomic() کو ایٹم آپریشنز کو پورا کرنے کے لیے لین دین بنانے کے لیے استعمال کیا جا سکتا ہے - DB آپریشنز جو کہ سبھی کو انجام دینے اور ایک ساتھ محفوظ ہونے یا ناکام ہونے کی ضمانت ہیں۔ Django بنیادی DB کے لین دین کے طریقہ کار کا استعمال کرتے ہوئے لین دین کرتا ہے، یہ لین دین میں کوڈ کو انجام دیتا ہے، اور اگر کوئی خرابی نہیں ہوتی ہے، تو یہ DB کو لین دین کا ارتکاب کرتا ہے۔
featured image - ازگر: جینگو ٹرانزیکشنز کیسے کام کرتی ہیں اس پر گہری نظر
Michael T. Andemeskel HackerNoon profile picture
0-item


مواد

  • TLDR - جینگو ٹرانزیکشن منطق کا خلاصہ
  • منطق کا خاکہ
  • لین دین اور اٹامک آپریشنز
  • جینگو میں لین دین
  • جینگو آٹو کمٹ موڈ - خودکار لین دین کو بند کرنا
  • ذرائع

TLDR - جینگو ٹرانزیکشن منطق کا خلاصہ

یہ PSQL یا دیگر اسی طرح کے SQL (SQLite, MySQL، وغیرہ) پر مبنی ڈیٹا بیس (DBs) کے ساتھ Django چلانے والی ایپس کے لیے ہے۔ لین دین کے بارے میں بنیادی اصول دوسرے DBs پر لاگو نہیں ہوسکتے ہیں۔ ہڈ کے نیچے، Django کا لین دین کا انتظام کوڈ مندرجہ ذیل کام کرتا ہے (یہ Django کے doc سے کاپی کیا گیا ہے - وضاحت کے لیے میرے اپنے بلٹ پوائنٹس کے ساتھ نیچے سکرول کریں):


  • بیرونی ترین ایٹم بلاک میں داخل ہونے پر لین دین کھولتا ہے۔
    • DB سے کنکشن حاصل کرتا ہے یا بناتا ہے اور اسے لین دین کے طور پر سیٹ کرتا ہے۔


  • جب ڈی بی آپریشن کا سامنا ہوتا ہے تو تالے کی درخواست کرتا ہے اور حاصل کرتا ہے۔
    • تمام DB آپریشنز کو تالے کی ضرورت ہوتی ہے — کچھ تالے ڈھیلے ہوتے ہیں اور دوسرے کنکشنز کو اسی وسائل پر آپریشن کرنے کی اجازت دیتے ہیں، لیکن دوسرے تالے زیادہ سخت ہوتے ہیں۔ وہ خصوصی ہیں اور پڑھنے اور لکھنے دونوں کاموں کو روک دیں گے۔ ریکارڈز بنانے، اپ ڈیٹ کرنے اور حذف کرنے کے ساتھ ساتھ جدولوں اور کالموں کو تبدیل کرنے سے مزید سخت تالے حاصل ہوں گے جو دوسرے کنکشنز کو آپریشن کرنے سے روک دیں گے۔ یہ تالے لین دین کے اختتام تک رکھے جاتے ہیں۔


  • اندرونی ایٹم بلاک میں داخل ہونے پر ایک سیو پوائنٹ بناتا ہے۔
    • یہ خود بخود ہو جاتا ہے جب، مثال کے طور پر، ریکارڈز کو ٹیبل میں داخل کرنا — کچھ ماڈل آپریشنز خود بخود خود کو ایٹم بلاکس میں لپیٹ لیں گے۔

    • یہ دستی طور پر کسی ایسے فنکشن کو کال کرکے کیا جا سکتا ہے جسے اٹامک() کے ذریعے لپیٹ دیا گیا ہو یا اٹامک() کا استعمال کرتے ہوئے بیان کے ساتھ (ایک سیاق و سباق کے مینیجر کے طور پر)۔

    • Savepoints وہی کنکشن استعمال کرے گا جو بیرونی لین دین کی طرح ہوتا ہے — اگر آپ سیو پوائنٹس کے لیے Django کوڈ کو دیکھیں تو یہ ایک اور ٹرانزیکشن بنانے کے لیے صرف ایک تکراری کال ہے۔

    • سیو پوائنٹس کو سیو پوائنٹس کے اندر اندر بنایا جا سکتا ہے - ایک اسٹیک سیو پوائنٹس کو ٹریک کرتا ہے۔


  • اندرونی بلاک سے باہر نکلتے وقت سیو پوائنٹ پر ریلیز یا رول بیک کرتا ہے۔
    • داخل کرنے کے بعد، سیو پوائنٹ کو یا تو تبدیلیاں کر کے اور باقی ٹرانزیکشن (لیکن دوسرے کنکشنز نہیں) کے لیے دستیاب کر کے یا تبدیلیوں کو واپس کر کے ہٹا دیا جاتا ہے۔


  • جب DB کو چھونے والا کوڈ سامنے نہیں آتا ہے تو کوڈ کو معمول کے مطابق عمل میں لایا جاتا ہے۔
    • DB پر تالے ابھی بھی رکھے گئے ہیں جب کہ نان DB منطق پر عمل کیا جاتا ہے، مثلاً، اگر ہم کسی لین دین کے باڈی میں HTTP درخواست بھیجتے ہیں، تو تالے اس وقت تک رکھے جائیں گے جب تک کہ وہ درخواست نہیں بھیجی جاتی اور جواب واپس نہیں آ جاتا۔ جب ہم DB آپریشنز کو انجام دینا بند کر دیتے ہیں تو Django تالے جاری نہیں کرتا ہے۔ بیرونی لین دین ختم ہونے تک یہ تالے رکھتا ہے۔

    • نیسٹڈ ٹرانزیکشنز میں حاصل کیے گئے تالے بھی اس وقت تک رکھے جاتے ہیں جب تک کہ بیرونی ٹرانزیکشن مکمل نہ ہو جائے یا نیسٹڈ ٹرانزیکشن واپس نہ کر دی جائے۔


  • جب رن ٹائم ایرر واقع ہوتا ہے یا ڈی بی کے باہر کوئی خرابی پیدا ہوتی ہے (ڈی بی آپریشنز سے متعلق نہیں)؛
    • لین دین روک دیا جاتا ہے، واپس لوٹا جاتا ہے، اور تالے جاری کیے جاتے ہیں۔

    • اگر غلطی نیسٹڈ ٹرانزیکشن میں ہوتی ہے تو بیرونی لین دین متاثر نہیں ہوتا ہے۔ رول بیک ہوتا ہے لیکن بیرونی لین دین بلاتعطل جاری رہ سکتا ہے (جب تک کہ ابھری ہوئی غلطی کو پکڑا اور سنبھال لیا جائے)۔

    • لین دین غلطیاں نہیں پکڑتے ہیں، لیکن وہ ان پر انحصار کرتے ہیں تاکہ یہ جان سکیں کہ تبدیلیوں کو کب واپس لانا ہے۔ اس لیے، ڈی بی آپریشنز کو کوشش/سوائے میں لپیٹ نہ کریں، اس کے بجائے، انہیں ٹرانزیکشن میں لپیٹیں اور پھر ٹرانزیکشن کو ٹرائی/سوائے میں لپیٹیں۔ ایسا کرنے سے DB آپریشن ناکام ہوجاتا ہے اور بیرونی لین دین کو متاثر کیے بغیر خود بخود واپس چلا جاتا ہے۔


  • بیرونی بلاک سے باہر نکلتے وقت لین دین کا ارتکاب یا رول بیک کرتا ہے۔
    • آخر میں، تمام لین دین کا عہد کیا جاتا ہے، تبدیلیاں تمام DB صارفین/ کنکشنز کے لیے دستیاب ہوتی ہیں۔ یا اسے واپس موڑ دیا جاتا ہے، ڈی بی کو اسی حالت میں چھوڑ دیا جاتا ہے جیسا کہ لین دین کا سامنا کرنے کے وقت تھا۔


اگلے بلاگ میں، میں اس کے بارے میں لکھوں گا کہ آپ کو لین دین میں کیا کرنا چاہیے یا نہیں کرنا چاہیے تاکہ لاک بھوک کی وجہ سے ہونے والی بندش سے بچا جا سکے۔

منطق کا خاکہ

جیانگو ٹرانزیکشنز کا منطقی خاکہ — مکمل

لین دین اور اٹامک آپریشنز

لین دین وہ طریقہ کار ہیں جو ACID DB's (PSQL, SQL, latest MongoDB ، وغیرہ) کو ATOMIC (ACID میں A) ہونے کی اجازت دیتے ہیں۔ اس کا مطلب ہے کہ DB کو لکھے گئے تمام خطوط ایک ہی آپریشن کے طور پر کیے جاتے ہیں - چاہے کتنا ہی پیچیدہ ہو۔ اگر تحریر کامیاب ہو جاتی ہے تو، DB میں تمام تبدیلیاں برقرار رہتی ہیں اور بیک وقت تمام کنکشنز کے لیے دستیاب ہوتی ہیں (کوئی جزوی نہیں لکھتا)۔ اگر تحریر ناکام ہو جاتی ہے تو، تمام تبدیلیاں واپس کر دی جاتی ہیں — دوبارہ، کوئی جزوی تبدیلیاں نہیں ہیں۔


لین دین ان اصولوں کی ضمانت دیتا ہے:

  • ڈی بی میں ڈیٹا ٹرانزیکشن کے وسط میں تبدیل نہیں ہوگا۔
  • لین دین کے مکمل ہونے تک کوئی دوسرا کنکشن اس کے ذریعے کی گئی تبدیلیوں کو نہیں دیکھ سکے گا۔
  • ڈی بی کے پاس یا تو تمام نیا ڈیٹا ہوگا یا اس میں سے کوئی بھی نہیں۔


یہ قواعد DB کے صارف کو پیچیدہ آپریشنز کو ایک ساتھ باندھنے اور انہیں ایک آپریشن کے طور پر انجام دینے کی اجازت دیتے ہیں۔ مثال کے طور پر، ایک بینک اکاؤنٹ سے دوسرے اکاؤنٹ میں منتقلی پر عمل درآمد؛ اگر ہمارے پاس لین دین نہیں تھا، تو ان دو تحریری کارروائیوں کے بیچ میں، واپسی یا یہاں تک کہ ایک قریبی اکاؤنٹ آپریشن ہوسکتا ہے جو منتقلی کو غلط بنا دیتا ہے۔ لین دین صارف کو ٹریفک کنٹرول کی کسی نہ کسی شکل کی اجازت دیتا ہے۔ ٹرانزیکشن جاری ہونے کے دوران ہم دیگر تمام متضاد کارروائیوں کو روک سکتے ہیں۔


آپریشن میزوں اور قطاروں پر تالے کی ایک سیریز کے ذریعے مسدود ہیں۔ PSQL اور دیگر SQL متغیرات میں، لین دین BEGIN کے ساتھ بنائے جاتے ہیں۔ پھر تالے حاصل کیے جاتے ہیں جب ایک آپریشن جیسا کہ Select/insert/delete/alter چلایا جاتا ہے اور لین دین COMMIT یا ROLLBACK کے ساتھ ختم ہوتا ہے۔ جب COMMIT یا ROLLBACK عمل میں لایا جاتا ہے تو تالے جاری کیے جاتے ہیں۔ خوش قسمتی سے، جینگو ہمیں ان تین بیانات کو استعمال کیے بغیر لین دین کرنے کی اجازت دیتا ہے (لیکن ہمیں ابھی بھی تالے کے بارے میں فکر کرنے کی ضرورت ہے؛ اس پر مزید اگلی پوسٹ میں)۔


 -- Start a new transaction BEGIN; SELECT … INSERT INTO … UPDATE … DELETE FROM … -- Save the changes COMMIT;


  • سلیکٹ ایسے تالے حاصل کرتا ہے جو پڑھی جانے والی قطاروں پر اپ ڈیٹس کو روکتا ہے۔
  • داخل کرنے سے ایسے تالے حاصل ہوتے ہیں جو بنائی جانے والی قطاروں پر اپ ڈیٹس کو روکتے ہیں۔
  • اپ ڈیٹ ایسے تالے حاصل کرتا ہے جو اپ ڈیٹ ہونے والی قطاروں پر اپ ڈیٹس کو روکتا ہے۔
  • حذف کرنے سے ایسے تالے حاصل ہوتے ہیں جو حذف ہونے والی قطاروں پر اپ ڈیٹس کو روکتے ہیں۔
  • ہمیں واضح طور پر غلطیوں کی جانچ کرنے اور ROLLBACK کال کرنے کی ضرورت نہیں ہے — لین دین ہمارے لیے ایسا کرتا ہے۔
  • اگر وہاں ایک الٹر ٹیبل آپریشن ہوتا ہے، تو یہ میز پر تمام پڑھنے اور لکھنے کو روک دے گا (اگلے بلاگ میں اس پر مزید)۔

جینگو میں لین دین

 from django.db import transaction from app.core.models import Accounts, Fee, NotificationJob def do_migration(): overdrawn_accounts = Accounts.objects.filter(type='overdrawn') for acount in overdrawn_accounts: create_notification(acount) @transaction.atomic def create_notification(acount: Accounts): # $5 fee for overdraft - 500 because we never store money as float!!! recall = Fee.objects.create(acount=acount, description='Fee for overdraft', amount=500) NotificationJob.objects.create(recall=recall, notification_type='all') acount.status = 'awaiting_payment' acount.save() def do_migration2(): overdawn_account = Accounts.objects.filter(type='overdrawn') for account in overdawn_account: with transaction.atomic(): recall = Fee.objects.create(acount=account, description='Fee for overdraft', amount=500) NotificationJob.objects.create(recall=recall, notification_type='all') account.status = 'awaiting_payment' account.save()


جب آٹوکومٹ موڈ میں چلتا ہے تو Django ہر DB آپریشن کو خود بخود ہمارے لیے لین دین میں لپیٹ دیتا ہے (نیچے اس پر مزید)۔ ایٹم() ڈیکوریٹر یا سیاق و سباق کے مینیجر (ایٹم() کے ساتھ استعمال کرتے ہوئے واضح لین دین کی جا سکتی ہے — جب ایٹم() استعمال کیا جاتا ہے، انفرادی DB آپریشنز کسی لین دین میں لپیٹے نہیں جاتے ہیں یا DB کے ساتھ فوری طور پر پابند نہیں ہوتے ہیں (ان پر عمل درآمد کیا جاتا ہے، لیکن DB میں تبدیلیاں دوسرے صارفین کو نظر نہیں آتی ہیں)۔ اس کے بجائے، پورے فنکشن کو ٹرانزیکشن بلاک میں لپیٹ دیا جاتا ہے اور آخر میں ارتکاب کیا جاتا ہے (اگر کوئی غلطی نہیں کی جاتی ہے) — COMMIT کو عمل میں لایا جاتا ہے۔


اگر غلطیاں ہوں تو، DB تبدیلیاں واپس کر دی جاتی ہیں — ROLLBACK کو عمل میں لایا جاتا ہے۔ یہی وجہ ہے کہ لین دین آخر تک تالے میں ہی رہتا ہے۔ ہم کسی ٹیبل پر لاک جاری نہیں کرنا چاہتے، کوئی دوسرا کنکشن ٹیبل کو تبدیل کریں یا اسے پڑھیں، اور پھر جو کچھ تبدیل یا پڑھا گیا ہے اسے واپس کرنے پر مجبور کیا جائے۔


 ANGRY_CUSTOMER_THRESHOLD = 3 @transaction.atomic def create_notification(acount: Accounts): recall = Fee.objects.create(acount=acount, description='Fee for overdraft', amount=500) NotificationJob.objects.create(recall=recall, notification_type='all') try: # when this completes successfully, the changes will be available to the outer transaction with transaction.atomic(): owner = acount.owner fees = Fee.objects.filter(owner=owner).count() if fees >= ANGRY_CUSTOMER_THRESHOLD: for fee in fees: fee.amount = 0 fee.save() owner.status = 'angry' owner.save() # as long as we catch the error, the outer transaction will not be rolled back except Exception as e: logger.error(f'Error while removings fees for account {acount.id}: {e}') acount.status = 'awaiting_payment' acount.save()


ہم کسی دوسرے فنکشن کو کال کرکے یا لین دین کے اندر سیاق و سباق کے مینیجر کا استعمال کرتے ہوئے لین دین کو نیسٹ کرسکتے ہیں۔ اس سے ہمیں محفوظ پوائنٹس بنانے کی اجازت ملتی ہے جہاں ہم باقی لین دین کو متاثر کیے بغیر پرخطر کارروائیوں کی کوشش کر سکتے ہیں — جب کسی اندرونی لین دین کا پتہ چل جاتا ہے، ایک سیو پوائنٹ بنایا جاتا ہے، اندرونی لین دین پر عمل درآمد ہوتا ہے، اور اگر اندرونی لین دین ناکام ہو جاتا ہے، ڈیٹا کو واپس محفوظ کرنے والے مقام پر واپس لایا جاتا ہے اور بیرونی لین دین جاری رہتا ہے۔ اگر بیرونی لین دین ناکام ہو جاتا ہے تو، تمام اندرونی لین دین بیرونی لین دین کے ساتھ واپس کر دیے جاتے ہیں۔ Durable=True in atomic() کو ترتیب دے کر ٹرانزیکشن نیسٹنگ کو روکا جا سکتا ہے - اگر کسی اندرونی لین دین کا پتہ چلا تو یہ لین دین RuntimeError کو بڑھا دے گا۔


نیسٹڈ ٹرانزیکشنز کے بارے میں آپ کو کیا یاد رکھنے کی ضرورت ہے:

  • نیسٹڈ ٹرانزیکشنز تالے جاری نہیں کرتے ہیں جب تک کہ نیسٹڈ ٹرانزیکشنز کو رول بیک نہ کیا جائے یا بیرونی لین دین کمٹڈ یا رول بیک نہ کیا جائے۔
  • نیسٹڈ ٹرانزیکشنز DB کی غلطیوں کو نہیں پکڑتے ہیں۔ وہ صرف اس لین دین میں کارروائیوں کو واپس لے لیتے ہیں جس کی وجہ سے خرابی ہوئی تھی۔ بیرونی لین دین کو جاری رکھنے کے لیے ہمیں ابھی بھی DB کی غلطی کو پکڑنے کی ضرورت ہے۔
  • نیسٹڈ ٹرانزیکشنز میں کی گئی تبدیلیاں بیرونی ٹرانزیکشن اور اس کے بعد نیسٹڈ ٹرانزیکشنز کے لیے دستیاب ہیں۔

جینگو آٹوکمیٹ موڈ - خودکار لین دین کو بند کرنا

 DATABASES = { 'default': { # True by default 'AUTOCOMMIT': False, # ...rest of configs } }

ڈیفالٹ کے طور پر، Django آٹوکومٹ موڈ میں چلتا ہے، یعنی ہر DB آپریشن کو ٹرانزیکشن میں لپیٹ دیا جاتا ہے اور فوری طور پر چلایا جاتا ہے (پُرعزم، اس لیے آٹوکمیٹ) سوائے اس کے کہ صارف کے ذریعے کسی لین دین میں آپریشن کو واضح طور پر لپیٹ دیا گیا ہو۔ یہ بنیادی DB کی لین دین کی منطق کو مبہم کر دیتا ہے — کچھ DBs، جیسے PSQL، خود بخود تمام کارروائیوں کو لین دین میں سمیٹ دیتے ہیں جبکہ دوسرے ایسا نہیں کرتے۔ اگر ہمارے پاس Django ہمارے لیے ایسا کر رہا ہے، تو ہمیں بنیادی DB منطق کے بارے میں فکر کرنے کی ضرورت نہیں ہے۔


ہم آٹوکمیٹ موڈ کو بند کر سکتے ہیں، لیکن اس سے ہمیں آپریشنز کو منظم کرنے اور یہ یقینی بنانے کے لیے DB پر انحصار کرنا پڑے گا کہ وہ ATOMIC ہیں، جو ڈویلپرز کے لیے خطرناک اور تکلیف دہ ہے۔ یہ مزہ نہیں آئے گا اگر، ایک API بناتے وقت، ہمیں یہ معلوم کرنا پڑے کہ کون سے رائٹ آپریشنز لین دین میں ہیں اور اس لیے، کل لکھا جائے گا نہ کہ جزوی طور پر۔


تاہم، اگر ہمیں DB پر کنکشنز کی تعداد اور ان کے انجام دینے والے آپریشنز کی ترتیب معلوم ہو تو ہم آٹوکمیٹ موڈ کو بند کرنا چاہیں گے۔ اگر ہم یہ جان لیتے ہیں کہ ان آپریشنز کو کیسے ڈی کنفلیکٹ کیا جائے، تو ہم آٹو کمٹ موڈ کو آف کر سکتے ہیں اور کچھ افادیت حاصل کر سکتے ہیں:

  • ہم ہر آپریشن سے دو کمانڈز ہٹاتے ہیں: BEGIN اور COMMIT/ROLLBACK۔ لیکن زیادہ تر DB خود بخود ہر آپریشن کو لین دین میں لپیٹ دیتے ہیں لہذا یہ بے معنی ہو سکتا ہے۔
  • تالے زیادہ دیر تک نہیں رکھے جائیں گے - جیسے ہی کوئی آپریشن ختم ہوتا ہے، پورے لین دین کے ختم ہونے کا انتظار کرنے کے مقابلے میں، اس کے پاس موجود تالے جاری ہو جاتے ہیں۔
  • تعطل کا امکان کم ہوتا ہے — تعطل اس وقت ہوتا ہے جب دو ٹرانزیکشنز کو ایک لاک کی ضرورت ہوتی ہے جو دوسرے ٹرانزیکشن کے پاس ہوتا ہے۔ اس سے دونوں لین دین دوسرے کے ختم ہونے کا انتظار کرتے ہیں، لیکن کوئی بھی ختم نہیں ہو سکتا۔ تاہم، تعطل اب بھی ہو سکتا ہے۔ کچھ ڈی بی آپریشنز ایک سے زیادہ تحریریں کریں گے جیسے، ایک کالم کو اپ ڈیٹ کرنا جس پر انڈیکس ہے کالم اور انڈیکس کو اپ ڈیٹ کرے گا (کم از کم دو لکھتے ہیں)۔ اگر کوئی دوسرا کنکشن متاثرہ قطاروں یا کالموں پر کام کرنے کی کوشش کرتا ہے تو یہ تعطل کا باعث بن سکتا ہے۔


منفی پہلو ڈیٹا بدعنوانی کے زیادہ خطرات ہیں۔ یہ اس کے قابل نہیں ہے، لیکن ہوسکتا ہے کہ استعمال کا کوئی معاملہ ہو جس کے بارے میں میں سوچ بھی نہیں سکتا۔

ذرائع