1. لین دین اور ڈیٹا کا تعلق یقینی بنانا

ٹرانزیکشن، ڈیٹا بیس مینجمنٹ سسٹم کے اجراء کے مانیط کا ایک منطقی واحد ہوتا ہے، جس میں مختلف آپریشنز شامل ہوتے ہیں۔ یہ آپریشنز یا تو پورے ہوتے ہیں یا پورے نہیں ہوتے، اور انہیں ایک غیر تقسیم پذیر ہنجر کے طور پر سنجیدگی سے مانا جاتا ہے۔ ٹرانزیکشن کی کلیدی خصوصیات ACID کے طور پر مختصراً یوں بیان کی جا سکتی ہیں:

  • اتمیت: ٹرانزیکشن میں تمام آپریشنز یا تو مکمل طور پر مکمل ہوتے ہیں یا پورے نہیں ہوتے، جزوی مکملیت ممکن نہیں ہوتی۔
  • یکسانت: ٹرانزیکشن کا فعل ڈیٹا بیس کو ایک یکساں حالت سے دوسری یکساں حالت میں منتقل کرنا ہوتا ہے۔
  • الگی: ٹرانزیکشن کا اجراء دوسری ٹرانزیکشنوں کی مداخلت سے الگ ہونا چاہئے، اور متعدد متزامن ٹرانزیکشنز کے بیچ ڈیٹا الگ ہونا ہوتا ہے۔
  • دائمیت: جب ایک ٹرانزیکشن کی منظوری ہو جاتی ہے تو اس کے ذریعے کی گئی ترمیمات ڈیٹا بیس میں برقرار رہتی ہیں۔

ڈیٹا یکسانت کا مطلب ہے کہ ایک سلسلہ آپریشنز کے بعد ڈیٹا بیس میں صحیح اور درست حالت کو برقرار رکھنا۔ متزامن رسائی یا سسٹم کی خرابیوں کے سناریو میں، ڈیٹا یکسانت خاص طور پر اہم ہوتی ہے، اور ٹرانزیکشنز کو یہ یقینی بناتے ہیں کہ خرابی یا تضاد کے صورت میں بھی ڈیٹا کی یکسانت میں کوئی کمی نہیں آتی۔

2. ent فریم ورک کا جائزہ

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

3. ٹرانزیکشن شروع کرنا

3.1 ent میں ٹرانزیکشن شروع کرنا کیسے

ent فریم ورک میں، دیے گئے سیاق و سباق میں ایک نیا ٹرانزیکشن آسانی سے کسی موجودہ کنٹیکسٹ کے ذریعے client.Tx میتھڈ کا استعمال کرکے شروع کیا جا سکتا ہے، جو ایک Tx ٹرانزیکشن آبجیکٹ واپس کرتا ہے۔ کوڈ مثال مندرجہ ذیل ہے:

tx, err := client.Tx(ctx)
if err != nil {
    // ٹرانزیکشن شروع کرتے وقت خطوط کی غلطیوں کا سامنا کریں
    return fmt.Errorf("ٹرانزیکشن شروع کرتے وقت خرابی کا سامنا ہوا: %w", err)
}
// tx کا استعمال کر کے آئندہ آپریشنز کریں...

3.2 ٹرانزیکشن کے اندر کام کرنا

ایک بار Tx آبجکٹ کامیابی سے بنایا جاتا ہے، تو اسے ڈیٹا بیس آپریشنز کرنے کے لئے استعمال کیا جا سکتا ہے۔ تمام تخلیق، حذف، تازہ کاری اور کوئیری آپریشنز جو Tx آبجکٹ پر اجراء کی جاتی ہیں وہ سب ٹرانزیکشن کا حصہ بن جاتی ہیں۔ مندرجہ ذیل مثال میں ایک سلسلہ آپریشنز کا مشاہدہ کیا جا رہا ہے:

hub, err := tx.Group.
    Create().
    SetName("Github").
    Save(ctx)
if err != nil {
    // اگر کوئی خرابی ہوتی ہے، تو ٹرانزیکشن کو روک دیا جائے گا
    return rollback(tx, fmt.Errorf("گروپ تخلیق کرنے میں ناکامی: %w", err))
}
// یہاں مزید آپریشنز شامل کی جا سکتی ہیں...
// ٹرانزیکشن کو منظور کریں
tx.Commit()

4. خرابی کا نجاح مند انتظام اور رول بیک

4.1 خرابی کا نجاح مند انتظام کی اہمیت

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

4.2 رول بیک کو کیسے لاگو کریں

ent فریم ورک میں، آپ Tx.Rollback() میتھڈ کا استعمال کرکے پوری ٹرانزیکشن کو رول بیک کرنے کے لئے استعمال کرسکتے ہیں۔ عموماً، ایک rollback مددگار فنکشن کو تعریف کیا جاتا ہے تاکہ رول بیک اور خرابیوں کا انتظام کیا جا سکے، جیسا کہ مندرجہ ذیل میں دکھایا گیا ہے:

func rollback(tx *ent.Tx, err error) error {
    if rerr := tx.Rollback(); rerr != nil {
        // اگر رول بیک ناکام رہے، تو اصل خرابی اور رول بیک خرابی ساتھ ساتھ واپسی کریں
        err = fmt.Errorf("%w: رول بیک کرتے وقت خرابی ہوئی: %v", err, rerr)
    }
    return err
}

اس rollback فنکشن کے ساتھ، ہم خرابیوں اور ٹرانزیکشن رول بیک کو محفوظی سے منظم کر سکتے ہیں۔ یہ یقینی بناتا ہے کہ کسی بھی خرابی کے صورت میں بھی ڈیٹا بیس کی یکسانت پر منفی اثر نہیں ہوتا۔

5. ٹرانزیکشنل کلائنٹ کا استعمال

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

// اس مثال میں، ہم اصل Gen فنکشن کو ایک ٹرانزیکشن کے اندر چھپاتے ہیں۔
func WrapGen(ctx context.Context, client *ent.Client) error {
    // پہلے، ایک ٹرانزیکشن بنائیں
    tx, err := client.Tx(ctx)
    if err != nil {
        return err
    }
    // ٹرانزیکشن سے ٹرانزیکشنل کلائنٹ حاصل کریں
    txClient := tx.Client()
    // اصل Gen فنکشن کو تبدیل کرنے کے بغیر ٹرانزیکشنل کلائنٹ کا استعمال کرکے Gen فنکشن کو چلایں
    if err := Gen(ctx, txClient); err != nil {
        // اگر کوئی خرابی آئی تو ٹرانزیکشن واپس لیں
        return rollback(tx, err)
    }
    // اگر کامیاب ہوگئے تو ٹرانزیکشن کو منظور کریں
    return tx.Commit()
}

اوپر دیے گئے کوڈ میں ٹرانزیکشنل کلائنٹ tx.Client() استعمال ہوتا ہے، جو اصل Gen فنکشن کو ٹرانزیکشن کی یقین دہانی کے تحت چلانے کی اجازت دیتا ہے۔ یہ ترکیب ہمیں موجودہ غیر تراکشنل کوڈ کو اصل منطق پر کم اثرات میں ٹرانزیکشنل کوڈ میں منتقل کرنے کی اجازت دیتی ہے۔

6. ٹرانزیکشن کے بہترین اصول

6.1 کال بیک فنکشن کے ذریعے ٹرانزیکشن کا انتظام

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

func WithTx(ctx context.Context, client *ent.Client, fn func(tx *ent.Tx) error) error {
    tx, err := client.Tx(ctx)
    if err != nil {
        return err
    }
    // ممکنہ پینک سیناریوز کا سامنا کرنے کے لیے defer اور recover کا استعمال کریں
    defer func() {
        if v := recover(); v != nil {
            tx.Rollback()
            panic(v)
        }
    }()
    // فراہم کردہ کال بیک فنکشن کو بلانے کے لیے
    if err := fn(tx); err != nil {
        // خرابی کی صورت میں، ٹرانزیکشن واپس لیں
        if rerr := tx.Rollback(); rerr != nil {
            err = fmt.Errorf("%w: rolling back transaction: %v", err, rerr)
        }
        return err
    }
    // اگر بزنس منطق خرابی سے آزاد ہو، تو ٹرانزیکشن کو منظور کریں
    return tx.Commit()
}

WithTx فنکشن کا استعمال کرکے ہم بزنس منطق کو چھانٹنے سے یقینی بنا سکتے ہیں کہ اگر بزنس منطق میں خرابی یا استثنائی صورتحال واقع ہوتی ہے تو ٹرانزیکشن درست طریقے سے ہینڈل ہوگا (منظور یا واپس لیا جائے گا)۔

6.2 ٹرانزیکشن ہکس کا استعمال

سکیما ہکس اور رن ٹائم ہکس کے مماثل، ہم فعال ٹرانزیکشن (Tx) کے اندر ہکس رجسٹر کرسکتے ہیں جو Tx.Commit یا Tx.Rollback پر ٹرگر ہوگا۔

func Do(ctx context.Context, client *ent.Client) error {
    tx, err := client.Tx(ctx)
    if err != nil {
        return err
    }
    tx.OnCommit(func(next ent.Committer) ent.Committer {
        return ent.CommitFunc(func(ctx context.Context, tx *ent.Tx) error {
            // ٹرانزیکشن منظور کرنے سے پہلے منطق
            err := next.Commit(ctx, tx)
            // ٹرانزیکشن منظور کرنے کے بعد منطق
            return err
        })
    })
    tx.OnRollback(func(next ent.Rollbacker) ent.Rollbacker {
        return ent.RollbackFunc(func(ctx context.Context, tx *ent.Tx) error {
            // ٹرانزیکشن واپس لینے سے پہلے منطق
            err := next.Rollback(ctx, tx)
            // ٹرانزیکشن واپس لینے کے بعد منطق
            return err
        })
    })
    // دیگر بزنس منطق کو چلائیں
    //
    // 
    //
    return err
}

ٹرانزیکشن منظوری اور واپس لینے کے دوران ہکس جوڑنے سے ہم اضافی منطق کو ہینڈل کرسکتے ہیں، جیسے کہ لاگنگ یا وسائل کی صفائی۔

7. مختلف ٹرانزیکشن علیحدگی سطح کو سمجھنا

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

  • ناپاک پڑھنا: سب سے کم سطح، جو ترقی کی گئی ڈیٹا کی پڑھائی ممکن بناتا ہے جو کہ ابھی تک منظور نہیں کی گئی ہے، جو ناپاک پڑھانا، غیر دہرانے والی پڑھائیاں، اور جنوں پڑھنے کی وجہ بن سکتا ہے۔
  • دہرانے والی پڑھائیاں: ڈیٹا کی پڑھائی اور منظور کرنے کی اجازت دیتا ہے، ناپاک پڑھائیاں کو روکتا ہے لیکن غیر دہرانے والی پڑھائیاں اور جنوں پڑھنا ممکن ہے۔
  • تکراری پڑھنا: یہ یقینی بناتا ہے کہ ایک ہی ڈیٹا کو ایک ہی ٹرانزیکشن میں متعدد بار پڑھنے سے مسلسل نتائج پیدا ہوتے ہیں، ناپاک پڑھائیاں روکتا ہے لیکن جنوں پڑھنا اور غیر دہرانے والی پڑھائیاں ممکن ہیں۔
  • سیریالائزیبل: سخت ترین علیحدگی سطح، جو Aٹرانزیکشن میں ملوث ڈیٹا کو قید کرکے ناپاک پڑھائیاں، غیر دہرانے والی پڑھائیاں، اور جنوں پڑھنے کی کوشش کرتا ہے۔

ent میں، اگر ڈیٹا بیس ڈرائیور علیحدگی سطح تعین کرنے کی حمایت کرتا ہے، تو یہ مندرجہ ذیل طریقے سے سیٹ کی جا سکتی ہے:

// علیحدگی سطح کو تکراری پڑھائی میں تبدیل کریں
tx، err := client.BeginTx(ctx، &sql.TxOptions{Isolation: sql.LevelRepeatableRead})

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