लारवेल: कोशिश ... DB के साथ पकड़ :: लेनदेन ()


85

हम सभी DB::transaction()कई सम्मिलित प्रश्नों के लिए उपयोग करते हैं। ऐसा करते समय, try...catchइसे अंदर रखा जाना चाहिए या इसे लपेटना चाहिए? क्या यह भी आवश्यक है कि try...catchजब कुछ गलत हो जाए तो लेनदेन स्वचालित रूप से विफल हो जाएगा?

try...catchएक लेनदेन लपेटकर नमूना :

// try...catch
try {
    // Transaction
    $exception = DB::transaction(function() {

        // Do your SQL here

    });

    if(is_null($exception)) {
        return true;
    } else {
        throw new Exception;
    }

}
catch(Exception $e) {
    return false;
}

विपरीत, एक DB::transaction()कोशिश लपेटकर ... पकड़:

// Transaction
$exception = DB::transaction(function() {
    // try...catch
    try {

        // Do your SQL here

    }
    catch(Exception $e) {
        return $e;
    }

});

return is_null($exception) ? true : false;

या बस एक लेनदेन w / o कोशिश ... पकड़

// Transaction only
$exception = DB::transaction(function() {

    // Do your SQL here

});

return is_null($exception) ? true : false;

जवाबों:


186

मामले आप कोड के माध्यम से मैन्युअल 'exit' लेन-देन करने की जरूरत में (एक अपवाद के माध्यम से यह हो या बस एक त्रुटि राज्य जाँच) आप उपयोग नहीं करना चाहिए DB::transaction(), लेकिन इसके बजाय में अपने कोड लपेट DB::beginTransactionऔर DB::commit/ DB::rollback():

DB::beginTransaction();

try {
    DB::insert(...);
    DB::insert(...);
    DB::insert(...);

    DB::commit();
    // all good
} catch (\Exception $e) {
    DB::rollback();
    // something went wrong
}

लेन-देन डॉक्स देखें ।


इसे फिर से देखने के बाद, यह वह उत्तर है जिसकी मुझे तलाश थी। :)
मुग्ध

@alexrussell - डेटाबेस एक अलग उत्पन्न नहीं करता है \Exception? मैं इसे इस सामान्य के साथ पकड़ सकता हूं \Exception? महान अगर यह है!
अर्तुर ममेदोव

बीच क्या अंतर है DB::beginTransaction()और DB:transaction()?
कामरेड

2
सरल प्रश्न: यदि आप अपवाद के बाद रोलबैक नहीं करते हैं या आप अपवाद नहीं पकड़ते हैं तो क्या होगा? स्क्रिप्ट खत्म होने के बाद ऑटो रोलबैक?
neoteknic

2
@HengSopheak यह सवाल लारवेल 4 डेटाबेस के बारे में था इसलिए यह बहुत संभव है कि मेरा जवाब अब 5.3 के लिए सही नहीं है। यह सही समुदाय समर्थन पाने के लिए लारवेल 5.3 टैग के साथ एक नया प्रश्न पूछने के लायक हो सकता है।
एलेक्स्रसेल

25

यदि आप PHP7 का उपयोग करते हैं, तो उपयोगकर्ता अपवादों और घातक त्रुटियों को पकड़ने के लिए थ्रोबेबल का उपयोग catchकरें।

उदाहरण के लिए:

DB::beginTransaction();

try {
    DB::insert(...);    
    DB::commit();
} catch (\Throwable $e) {
    DB::rollback();
    throw $e;
}

यदि आपका कोड PHP5 के साथ संगत होना चाहिए, तो उपयोग करें Exceptionऔर Throwable:

DB::beginTransaction();

try {
    DB::insert(...);    
    DB::commit();
} catch (\Exception $e) {
    DB::rollback();
    throw $e;
} catch (\Throwable $e) {
    DB::rollback();
    throw $e;
}

इस तथ्य के बारे में क्या है कि DB :: startTransaction () भी फेंक सकता है \ अपवाद? क्या इसे कोशिश / पकड़ में शामिल किया जाना चाहिए?
माइकल Pawlowsky

4
यदि लेन-देन शुरू नहीं किया गया है, तो हमें कुछ भी रोलबैक करने की आवश्यकता नहीं है। मोरेथ, catchब्लॉक में लेनदेन शुरू नहीं करने के लिए रोलबैक की कोशिश करना अच्छा नहीं है । इसलिए ब्लॉक DB::beginTransaction()से पहले अच्छी जगह है try
निक 23

12

आप लेन-देन try..catch से अधिक या यहाँ तक कि ,, अगर आप गहरे अंदर देखो लपेटकर सकता है उन्हें अपने उदाहरण कोड मैं laravel 5 में करने के लिए इस्तेमाल रिवर्स, यहाँ DB:transaction()में Illuminate\Database\Connectionहै कि आप की तरह एक ही मैनुअल लेनदेन लिखें।

लारवेल लेन-देन

public function transaction(Closure $callback)
    {
        $this->beginTransaction();

        try {
            $result = $callback($this);

            $this->commit();
        }

        catch (Exception $e) {
            $this->rollBack();

            throw $e;
        } catch (Throwable $e) {
            $this->rollBack();

            throw $e;
        }

        return $result;
    }

इसलिए आप अपना कोड इस तरह से लिख सकते हैं, और अपने अपवाद को संभाल सकते हैं जैसे आपके संदेश को फ्लैश के माध्यम से वापस फेंकना या किसी अन्य पृष्ठ पर पुनर्निर्देशित करना। क्लोजर के अंदर रिमेंबर रिटर्न लेन-देन में वापस आ जाता है () इसलिए यदि आप वापस लौटते हैं तो redirect()->back()यह तुरंत रीडायरेक्ट नहीं होगा, क्योंकि यह वेरिएबल में वापस आ जाता है जो ट्रांजैक्शन को हैंडल करता है।

लपेटें लेन-देन

$result = DB::transaction(function () use ($request, $message) {
   try{

      // execute query 1
      // execute query 2
      // ..

      return redirect(route('account.article'));

   } catch (\Exception $e) {
       return redirect()->back()->withErrors(['error' => $e->getMessage()]);
    }
 });

// redirect the page
return $result;

फिर विकल्प को बूलियन वेरिएबल फेंक दिया जाता है और लेनदेन फ़ंक्शन के बाहर पुनर्निर्देशित किया जाता है या यदि आपकी आवश्यकता को पुनः प्राप्त करना है तो लेनदेन विफल क्यों हुआ आप इसे $e->getMessage()अंदर से प्राप्त कर सकते हैंcatch(Exception $e){...}


मैंने
ट्राइ

@hamidrezasamsami हाँ, डेटाबेस स्वचालित रूप से वापस आ गया है, लेकिन कभी-कभी आपको यह जानना ज़रूरी है कि प्रश्न सभी सफल हैं या नहीं ..
अंगा अरी विजया

7
"रैप ट्रांजेक्शन" उदाहरण गलत है। यह हमेशा प्रतिबद्ध रहेगा, भले ही कोई भी प्रश्न विफल हो गया हो, क्योंकि सभी अपवाद लेनदेन कॉलबैक के भीतर पकड़े गए हैं। आप DB :: लेनदेन के बाहर की कोशिश करना / पकड़ना चाहते हैं।
Redmallard

3

मैंने इस सवाल का जवाब देने का फैसला किया है क्योंकि मुझे लगता है कि इसे हल किए गए ट्राइ-कैच ब्लॉक की तुलना में सरल सिंटैक्स का उपयोग करके हल किया जा सकता है। इस विषय पर लारवेल प्रलेखन बहुत संक्षिप्त है।

ट्राइ-कैच का उपयोग करने के बजाय, आप केवल DB::transaction(){...}इस तरह के रैपर का उपयोग कर सकते हैं :

// MyController.php
public function store(Request $request) {
    return DB::transaction(function() use ($request) {
        $user = User::create([
            'username' => $request->post('username')
        ]);

        // Add some sort of "log" record for the sake of transaction:
        $log = Log::create([
            'message' => 'User Foobar created'
        ]);

        // Lets add some custom validation that will prohibit the transaction:
        if($user->id > 1) {
            throw AnyException('Please rollback this transaction');
        }

        return response()->json(['message' => 'User saved!']);
    });
};

फिर आपको यह देखना चाहिए कि उपयोगकर्ता और लॉग रिकॉर्ड प्रत्येक अभिभावक के बिना मौजूद नहीं हो सकते।

उपरोक्त कार्यान्वयन पर कुछ नोट्स:

  • returnलेन-देन सुनिश्चित करें , ताकि आप response()इसके कॉलबैक के भीतर रिटर्न का उपयोग कर सकें ।
  • सुनिश्चित करें throwयदि आप चाहते हैं लेनदेन rollbacked जा करने के लिए एक अपवाद (या एक नेस्टेड समारोह है कि सुवक्ता के भीतर से अपने आप आपके लिए अपवाद फेंकता है, एक SQL अपवाद की तरह है)।
  • id, updated_at, created_atऔर किसी भी अन्य क्षेत्रों के लिए उपलब्ध होने के बाद निर्माण कर रहे हैं $userवस्तु (इस सौदे की अवधि के लिए)। लेन-देन आपके किसी भी निर्माण तर्क के माध्यम से चलेगा। फिर भी, जब AnyExceptionफेंक दिया जाता है तो पूरा रिकॉर्ड छोड़ दिया जाता है। इसका मतलब यह है कि उदाहरण के लिए एक ऑटो-इन्क्रीमेंट कॉलम idविफल लेनदेन पर बढ़ जाता है।

लारवेल 5.8 पर परीक्षण किया गया

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.