paint-brush
ازگر - جینگو: آپ کو اس چیز کو کبھی بھی لین دین میں نہیں رکھنا چاہئے۔کی طرف سے@mta
نئی تاریخ

ازگر - جینگو: آپ کو اس چیز کو کبھی بھی لین دین میں نہیں رکھنا چاہئے۔

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

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

Django ایپس میں لین دین مرکزی حیثیت رکھتے ہیں، لیکن اگر آپ لین دین میں غلط کوڈ ڈالتے ہیں، تو آپ کو بندش کا سبب بن سکتا ہے!
featured image - ازگر - جینگو: آپ کو اس چیز کو کبھی بھی لین دین میں نہیں رکھنا چاہئے۔
Michael T. Andemeskel HackerNoon profile picture


مواد

  • حصہ 1 کا خلاصہ - جیانگو لین دین میں گہرا غوطہ لگائیں۔
  • TLDR، خلاصہ
  • لین دین ہماری ایپس کو کیسے نقصان پہنچا سکتا ہے؟
  • میں
  • خطرناک
  • باہر
  • اگلا - پی ایس کیو ایل کمانڈز ایک دوسرے کو کیسے بلاک کرتی ہیں۔
  • ذرائع

حصہ 1 کا خلاصہ - جیانگو لین دین میں گہرا غوطہ لگائیں۔

پچھلی پوسٹ میں، ہم نے سیکھا تھا کہ جب transaction.atomic سے مزین فنکشن کہا جاتا ہے تو کیا ہوتا ہے اور with transaction.atomic() کیا ہوتا ہے۔ خلاصہ میں:


  1. ڈی بی سے ایک کنکشن بنایا یا بازیافت کیا جاتا ہے۔
  2. ایک لین دین بنتا ہے، جیسے، BEGIN; DB کو بھیجا جاتا ہے (اگر DB PSQL ہے یا دوسرا SQL متغیر ہے)۔
  3. اب سے جب تک فنکشن موجود ہے یا بیان کے ساتھ ختم نہیں ہوتا ہے - چاہے غلطی کے ساتھ ہو یا کامیابی کے ساتھ - ہم لین دین میں ہوں گے، اور DB ہمارا انتظار کر رہا ہوگا۔
  4. اس کا مطلب یہ ہے کہ (کم از کم ACID DBs جیسے PSQL کے لیے) ٹرانزیکشن میزوں اور قطاروں پر تالے رکھے گی جسے یہ تبدیل کر رہا ہے۔
  5. جب Django DB آپریشن کیا جاتا ہے، DB متعلقہ لاک کو پکڑ لیتا ہے اور اس ٹیبل یا قطار پر کسی بھی متضاد کارروائی کو روکتا ہے۔
  6. یہ لاک کے جاری ہونے کا انتظار کرنے کی وجہ سے دوسرے کنکشن کا وقت ختم ہونے کا سبب بن سکتا ہے۔
  7. اگر آپریشن ناکام ہو جاتا ہے یا رن ٹائم کی خرابی ہوتی ہے، تو DB پورے لین دین کو واپس کر دیتا ہے اور تالے جاری کر دیتا ہے۔
  8. اگر پورا لین دین کامیاب ہو جاتا ہے، تو تمام تبدیلیاں ارتکاب اور دیگر DB کنکشنز کے لیے دستیاب ہیں۔
  9. تالے جاری کیے گئے ہیں۔


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


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

TLDR، خلاصہ

میں

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

خطرناک

  • سست سوالات - ڈیٹا کی بازیافت عام طور پر تیز ہوتی ہے، سوائے ان تین منظرناموں کے۔ یہ استفسارات لین دین کو سست کر دیں گے اور اس کے لاک ہونے کے وقت کو بڑھا دیں گے، جس کے دوسرے صارفین پر منفی اثرات مرتب ہوں گے۔
  • ایک سے زیادہ ٹیبلز پر آپریشنز - ایک سے زیادہ ٹیبلز پر آپریشنز کے ساتھ ایک ٹرانزیکشن ہر ٹیبل کو لاک کر سکتا ہے جب تک کہ یہ مکمل نہ ہو جائے۔ یہ خاص طور پر جینگو کی نقل مکانی میں عام ہے - نقل مکانی کو چھوٹا رکھنے اور ایک وقت میں ایک یا چند میزوں پر توجہ مرکوز کرنے کی ایک اور وجہ۔
  • ڈیٹا مائیگریشنز - چونکہ ٹرانزیکشنز کو ایک لاک پر رکھا جاتا ہے جب تک کہ استفسار کیا جاتا ہے جب تک کہ ٹرانزیکشن ناکام ہو جائے یا ختم نہ ہو جائے، اس لیے ٹیبل کی ہر قطار پر چلنے والی منتقلی یا تو ہر قطار پر پڑھنے یا لکھنے کو روک کر پوری ٹیبل کو لاک کر دے گی۔
  • (صرف PSQL اور SQLite کے لیے*) ٹیبلز یا کالموں کو تبدیل کرنا - ان آپریشنز کے لیے تالے کی سخت ترین شکل کی ضرورت ہوتی ہے اور اس لیے یہ پوری ٹیبل پر پڑھنے/لکھنے کو روکیں گے۔ ان کارروائیوں میں بندش کا سب سے زیادہ امکان ہے۔

باہر

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


متبادل اور کوڈ کی مثالوں کے لیے پڑھتے رہیں۔

لین دین ہماری ایپس کو کیسے نقصان پہنچا سکتا ہے؟

بنیادی خطرہ یہ ہے کہ لین دین اس وقت تک تالے رکھتا ہے جب تک کہ وہ میزوں اور قطاروں پر متضاد کارروائیوں کو روکنے اور لین دین کو الٹ جانے کی اجازت دینے کے لیے مکمل نہ ہو جائیں - یہ ٹرانزیکشن میں DB کی کارروائیوں کو ایٹمی بنانے کے لیے ضروری ہے۔ اس کا مطلب یہ ہے کہ ایک طویل عرصے سے چلنے والا لین دین جو ایک سے زیادہ ٹیبلز پر چلتا ہے یا چند اہم لین دین میں بندش کا سبب بن سکتا ہے اور ان میزوں/قطاروں کو پڑھنے/لکھنے سے روکتا ہے۔


مختصراً، اگر ہم ٹرانزیکشن بلاک میں غلط کوڈ ڈالتے ہیں، تو ہم DB کے دیگر تمام کنکشنز کو اس پر کارروائی کرنے سے روک کر مؤثر طریقے سے DB کو ہٹا سکتے ہیں۔


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


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

میں

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

خطرناک

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


  • سست سوالات — ڈیٹا کی بازیافت عام طور پر تیز ہوتی ہے، سوائے ان تین منظرناموں کے۔ یہ استفسارات لین دین کو سست کر دیں گے اور اس کے لاک ہونے کے وقت کو بڑھا دیں گے، جس کے دوسرے صارفین پر منفی اثرات مرتب ہوں گے۔

    • مثالیں
      • انڈیکس شدہ کالموں پر سوالات
      • بڑی میزوں پر سوالات
      • شامل ہوتا ہے۔
     @transaction.atomic def process_large_order_report(start_date, end_date, min_order_value=1000): # Complex query with multiple joins and aggregations large_orders = Order.objects.filter( created_at__range=(start_date, end_date), total_amount__gte=min_order_value, status='completed' ).select_related( 'customer', 'shipping_address', 'billing_address' ).prefetch_related( 'items__product__category', 'items__product__supplier' ).annotate( item_count=Count('items'), total_weight=Sum('items__product__weight'), discount_percentage=F('discount_amount') * 100 / F('total_amount') ).filter( # Additional complex filtering Q(customer__user__is_active=True) & (Q(items__product__category__name='Electronics') | Q(items__product__category__name='Furniture')) & ~Q(shipping_address__country='US') ).order_by('-total_amount') # do the transactional work with the large_orders queryset
    • متبادل
      • یہ سوالات لین دین سے پہلے اور باہر کریں۔
 # fixed def process_large_order_report(start_date, end_date, min_order_value=1000): # Complex query with multiple joins and aggregations large_orders = Order.objects.filter( created_at__range=(start_date, end_date), total_amount__gte=min_order_value, status='completed' ).select_related( 'customer', 'shipping_address', 'billing_address' ).prefetch_related( 'items__product__category', 'items__product__supplier' ).annotate( item_count=Count('items'), total_weight=Sum('items__product__weight'), discount_percentage=F('discount_amount') * 100 / F('total_amount') ).filter( # Additional complex filtering Q(customer__user__is_active=True) & (Q(items__product__category__name='Electronics') | Q(items__product__category__name='Furniture')) & ~Q(shipping_address__country='US') ).order_by('-total_amount') # Start the transaction block with transaction.atomic(): # do the transactional work with the large_orders queryset


  • ایک سے زیادہ ٹیبلز پر آپریشنز - ایک سے زیادہ ٹیبلز پر آپریشنز کے ساتھ لین دین ہر ٹیبل کو اس وقت تک لاک کر سکتا ہے جب تک کہ یہ مکمل نہ ہو جائے۔ یہ خاص طور پر جینگو کی نقل مکانی میں عام ہے - نقل مکانی کو چھوٹا رکھنے اور ایک وقت میں ایک یا چند میزوں پر توجہ مرکوز کرنے کی ایک اور وجہ۔


    • مثالیں
      • ٹیبل یا کالم کا ڈھانچہ تبدیل کرنا دیکھیں
     class Migration(migrations.Migration): dependencies = [("migrations", "0001_initial")] # too many operations operations = [ migrations.RemoveField("Author", "age"), migrations.AddField("Author", "rating", models.IntegerField(default=0)), migrations.AlterField("Book", "price", models.DecimalField(max_digits=5, decimal_places=2)), ]
    • متبادل
      • لین دین کو متعدد چھوٹے لین دین میں تقسیم کریں اور انہیں آن کمٹ کال بیکس میں جوڑ دیں۔
 # fixed # 1st migration class Migration(migrations.Migration): dependencies = [("migrations", "0001_initial")] operations = [ migrations.RemoveField("Author", "age"), ] # 2nd migration class Migration(migrations.Migration): dependencies = [("migrations", "0002_initial")] operations = [ migrations.AddField("Author", "rating", models.IntegerField(default=0)), ] # 3rd migration class Migration(migrations.Migration): dependencies = [("migrations", "0003_initial")] operations = [ migrations.AlterField("Book", "price", models.DecimalField(max_digits=5, decimal_places=2)), ]


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

     def migrate_user_profiles(): # Get all users with legacy profiles users_with_profiles = User.objects.filter( legacy_profile__isnull=False ).select_related('legacy_profile') # Process all users in a single transaction with transaction.atomic(): # Track progress total = users_with_profiles.count() print(f"Migrating {total} user profiles...") # Process each user for i, user in enumerate(users_with_profiles): if i % 100 == 0: print(f"Processed {i}/{total} profiles") legacy = user.legacy_profile legacy.update_new_user_profile()
    • متبادل
      • لین دین کو انفرادی کارروائیوں کے گرد لپیٹیں، پوری منتقلی کے نہیں۔ لین دین میں ہر قطار میں اپ ڈیٹس ڈال کر، ہم صرف تھوڑے وقت کے لیے تالے کو تھامے رہتے ہیں۔
 # fixed def migrate_user_profiles(): # Get all users with legacy profiles users_with_profiles = User.objects.filter( legacy_profile__isnull=False ).select_related('legacy_profile') # Process all users in a single transaction # Track progress total = users_with_profiles.count() print(f"Migrating {total} user profiles...") # Process each user for i, user in enumerate(users_with_profiles): if i % 100 == 0: print(f"Processed {i}/{total} profiles") with transaction.atomic(): legacy = user.legacy_profile legacy.update_new_user_profile()


  • ( صرف PSQL اور SQLite کے لیے *) ٹیبل یا کالم تبدیل کرنا — ان آپریشنز کے لیے تالے کی سخت ترین شکل درکار ہوتی ہے اور اس لیے یہ پوری ٹیبل پر پڑھنے/لکھنے کو روکیں گے۔ ان کارروائیوں میں بندش کا سب سے زیادہ امکان ہے۔
    • مثال
      • کالم کو تبدیل کریں۔
      • الٹر ٹیبل
    • متبادل
      • انہیں بعد میں چلائیں۔ یہ سوالات ضروری ہیں، لیکن ہمیں انہیں کاروباری اوقات کے دوران چلانے کی ضرورت نہیں ہے۔ یہاں کی بہترین پالیسی یہ ہے کہ جدول کتنا اہم ہے، اس بات کا تعین کرکے کہ منتقلی میں کتنا وقت لگ سکتا ہے، منتقلی کو اس وقت انجام دینا جب DB کے پاس ٹریفک کم سے کم ہو، اور ایک رول بیک پلان تیار کرکے بندش کے خطرے کو کم کرنا ہے۔

      • لین دین میں جتنا وقت لگتا ہے اسے کم کریں۔ یہ ٹیبل کو تقسیم کرکے اور انفرادی پارٹیشنز پر ہجرت چلا کر کیا جا سکتا ہے۔ PSQL پارٹیشنز اور جینگو


*جیانگو صرف PSQL اور SQLite کی منتقلی کے ارد گرد لین دین کو سمیٹتا ہے۔

 class Migration(migrations.Migration): dependencies = [("migrations", "0001_initial")] # this migration, if on a large table, can slow down and block other operations # do it later operations = [ migrations.RemoveField("Users", "middle_name"), ]


باہر

  • ناقابل واپسی آپریشنز - لین دین میں ہر چیز کو الٹ جانا چاہیے اگر لین دین کو واپس کر دیا جائے؛ اگر ہم ٹرانزیکشن میں API کال کرتے ہیں، تو اسے کالعدم نہیں کیا جا سکتا۔

    • مثالیں
      • کسی ایونٹ کو قطار میں شامل کرنا — دوسرے واقعات کو متحرک کرنا
      • API کال بھیجنا — اسٹیٹس اپ ڈیٹس، ٹرگر جابز وغیرہ۔
     def transaction(user_data, user_files): with transaction.atomic(): user = User.objects.create(**user_data) async_notification_service.send_email(user.email, "You can login now!") Account.objects.create(user=user, balance=0) # rest of user creation proccess
    • متبادل
      • اہم کاروباری منطق کریں جو لین دین کے آن کمٹ کال بیک میں ہونے کی ضرورت ہے — آن کامیٹ کال بیک کو ہمیشہ ٹرانزیکشن کے کامیاب ہونے کے بعد کال کیا جاتا ہے، اور ٹرانزیکشن کی تمام اپ ڈیٹس آن کمٹ کال بیک میں دستیاب ہیں۔
      • ہم آپریشن کو الٹنے کے قابل بھی بنا سکتے ہیں، یعنی ایونٹس کو حذف کرنے یا انڈو API کال بھیجنے کا طریقہ تخلیق کر سکتے ہیں — یہ اس ٹیم کے لیے ایک غیر معمولی کام ہے جو ایونٹ کی قطار یا API کی مالک ہے۔ میں اس کی سفارش نہیں کرتا۔
 def transaction(user_data, user_files): with transaction.atomic(): user = User.objects.create(**user_data) Account.objects.create(user=user, balance=0) # rest of user creation proccess # the transaction is still in progress, so it can still be rolled back, it is not # committed until the transaction block is exited, so putting the notification here # is not a good idea - especially if the job starts immediately tries to read the data # this creates a race condition async_notification_service.send_email(user.email, "You can login now!") def transaction(user_data, user_files): with transaction.atomic(): user = User.objects.create(**user_data) Account.objects.create(user=user, balance=0) # rest of user creation proccess transaction.on_commit(partial(async_notification_service.send_email, user.email, "You can login now!"))


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


    • مثالیں
      • نیٹ ورک کالز — لین دین میں ڈالنے کے لیے ڈیٹا حاصل کرنے کے لیے APIs کو درخواستیں بھیجنا۔
      • لاگنگ اس کے تحت ہوتی ہے - ہم جو لاگر استعمال کرتے ہیں اس پر منحصر ہے، جب ہم لین دین میں ہوں تو لائبریری لاگز بھیج سکتی ہے، یا اگر ہم ڈیٹا ڈاگ استعمال کر رہے ہیں، تو اس میں لاگز کو محفوظ کرنے کا ایک اور عمل ہوگا، لیکن ہم پھر بھی لاگز کو میموری میں محفوظ کرنے کی قیمت ادا کرتے ہیں جب تک کہ بیچ جاب انہیں فائل میں محفوظ نہ کر لے۔
      • ڈسک آپریشنز - ٹیبل میں داخل کرنے کے لیے CSV لوڈ کرنا یا ٹیبل کو CSV میں ایکسپورٹ کرنا۔
      • CPU بھاری کام — میٹرکس ضرب یا کوئی بھاری ریاضی/ڈیٹا کی تبدیلی CPU اور دیگر تمام کارروائیوں کو روک دے گی — Python's Global Interpreter Lock ہر تھریڈ کو ایک وقت میں CPU استعمال کرنے پر مجبور کرتا ہے، اور Django سنگل پروسیسڈ ہوتا ہے (لین دین میں ہر آپریشن سلسلہ وار ہوتا ہے)۔
     def transaction(user_data, user_files): with transaction.atomic(): user = User.objects.create(**user_data) for file_data in user_files: # transaction waits for this upload and so do all other connections that need access to table/rows the transaction # uses url = Cloudinary.upload_file(file_data['data']) Files.objects.create(**file_data['meta_data'], user=user, url=url) Account.objects.create(user=user, balance=0) # rest of user creation proccess
    • متبادل
      • لین دین سے پہلے ڈیٹا تیار کریں — ڈسک/نیٹ ورک ڈیٹا پہلے سے لوڈ کریں۔ ڈیٹا تیار ہونے کے بعد، اس کے ساتھ لین دین کو انجام دیں۔
      • پلیس ہولڈر ڈیٹا کا استعمال کریں — ظاہری پلیس ہولڈر ڈیٹا کا ایک سیٹ بنائیں (اسے پروڈکشن ڈیٹا کے لیے غلطی کرنے کا کوئی طریقہ نہیں) جو آسانی سے بازیافت اور قابل شناخت ہو۔ لین دین سے پہلے اسے لوڈ کریں اور استعمال کریں۔
      • ڈیٹا تیار کریں - اگر فیلڈ میں انفرادیت کی رکاوٹیں ہیں جو پلیس ہولڈر ڈیٹا کو استعمال ہونے سے روکتی ہیں۔
      • یہ خطرناک ہے — یہ سیوڈو رینڈم الگورتھم کی نوعیت کی وجہ سے غیر متوقع ناکامیوں کا باعث بنے گا — اس لیے حیرت انگیز ناکامیوں سے بچنے کے لیے اچھے بیج کے ساتھ ایک اچھا رینڈم الگورتھم استعمال کریں۔
      • رکاوٹوں کو ہٹائیں یا ان میں ترمیم کریں — اگر رکاوٹیں ہمیں محفوظ طریقے سے اپنے ریکارڈ بنانے کی اجازت نہیں دے رہی ہیں، تو ہمارے اسکیما میں ایک مسئلہ ہے۔ رکاوٹوں کو ریاستی کالم پر منحصر بنائیں جو یہ بتاتا ہے کہ ریکارڈ کب مکمل ہے اور اس کی نگرانی کی جانی چاہئے۔
 # not bad def transaction(user_data, user_files): user = None with transaction.atomic(): user = User.objects.create(**user_data) Account.objects.create(user=user, balance=0) # rest of user creation proccess for file_data in user_files: url = Cloudinary.upload_file(file_data['data']) Files.objects.create(**file_data['meta_data'], user=user, url=url) # best fix from functools import partial def transaction(user_data, user_files): user = None with transaction.atomic(): user = User.objects.create(**user_data) Account.objects.create(user=user, balance=0) # rest of user creation proccess # partials create a callable with the function and arguments # so that the function is called with the arguments when the transaction is committed # TODO: diff between partial and lambda here??? transaction.on_commit(partial(create_user_files, user_files, user)) def create_user_files(user_files, user): for file_data in user_files: url = Cloudinary.upload_file(file_data['data']) Files.objects.create(**file_data['meta_data'], user=user, url=url)


اگلا — پی ایس کیو ایل کمانڈز ایک دوسرے کو کیسے بلاک کرتی ہیں۔

اگلی پوسٹ میں، ہم PSQL میں غوطہ لگائیں گے اور تلاش کریں گے:

  • مختلف کمانڈز میزوں اور قطاروں کو کیسے مقفل کرتے ہیں۔
  • کون سے احکامات پر عمل درآمد کرنا سب سے زیادہ خطرناک ہے۔

ذرائع

  • جوہری
  • جینگو ہجرت اور لین دین
    • DDL ٹرانزیکشنز (SQLite اور PostgreSQL) کو سپورٹ کرنے والے ڈیٹا بیسز پر، تمام مائیگریشن آپریشنز بطور ڈیفالٹ ایک ہی ٹرانزیکشن کے اندر چلیں گے۔ اس کے برعکس، اگر ڈیٹا بیس DDL ٹرانزیکشنز کو سپورٹ نہیں کرتا ہے (جیسے MySQL، Oracle) تو تمام آپریشنز بغیر کسی لین دین کے چلیں گے۔
    • آپ ایٹم انتساب کو False پر سیٹ کر کے ٹرانزیکشن میں ہجرت کو چلنے سے روک سکتے ہیں۔ مثال کے طور پر:
    • یہ بھی ممکن ہے کہ منتقلی کے کچھ حصوں کو لین دین کے اندر ایٹومک() کا استعمال کرتے ہوئے یا ایٹمک=ٹرو ٹو رن پائتھون کو پاس کرکے انجام دیا جائے۔
  • PSQL پارٹیشنز اور جینگو
    • جینگو کے ORM میں تقسیم شدہ میزوں کے لیے بلٹ ان سپورٹ نہیں ہے، لہذا اگر آپ اپنی ایپلی کیشن میں پارٹیشنز استعمال کرنا چاہتے ہیں، تو اس میں تھوڑا سا اضافی کام کرنا پڑے گا۔
    • پارٹیشنز کو استعمال کرنے کا ایک طریقہ یہ ہے کہ آپ اپنی ہجرت کو رول کریں جو خام SQL چلاتے ہیں۔ یہ کام کرے گا، لیکن اس کا مطلب ہے کہ آپ کو مستقبل میں میز پر کی جانے والی تمام تبدیلیوں کے لیے ہجرت کا انتظام دستی طور پر کرنا پڑے گا۔
    • دوسرا آپشن ایک پیکیج استعمال کرنا ہے جسے django-postgres-extra کہتے ہیں۔ Django-postgres-extra کئی PostgreSQL خصوصیات کے لیے سپورٹ پیش کرتا ہے جو Django کے ORM میں شامل نہیں ہیں، مثال کے طور پر TRUNCATE TABLE اور ٹیبل پارٹیشننگ کے لیے سپورٹ۔
  • PSQL ٹرانزیکشنز
  • ازگر: جینگو لین دین کیسے کام کرتا ہے۔