21 خرداد 1398 ساعت 08:26

Database Transactions چیست؟ آموزش Database Transactions در لاراول

transaction (ترنزاکشن) عملیاتی می باشد که به شما اجازه می دهد تا از صحت انجام یک فرآیند مطمئن و از درج ناقص اطلاعات جلوگیری کنید.تصور کنید شما قصد انجام یک سری عملیات حساس روی دیتابیس (حذف- افزودن- ویرایش ) دارید و باید مطمئن باشید که فرآیند تغییرات در SQL یا دیتابیس شما به درستی انجام شده است. برای اینکار شما میتوانید از قابلیت transaction در لاراول استفاده کنید.

Database Transactions چیست؟

transaction (ترنزاکشن) عملیاتی می باشد که به شما اجازه می دهد تا از صحت انجام یک فرآیند مطمئن و از درج ناقص اطلاعات جلوگیری کنید.

تصور کنید شما قصد انجام یک سری عملیات حساس روی دیتابیس (حذف- افزودن- ویرایش ) دارید و باید مطمئن باشید که فرآیند تغییرات در SQL یا دیتابیس شما به درستی انجام شده است. برای اینکار شما میتوانید از قابلیت transaction در لاراول استفاده کنید.

برای مثال ممکن است برای طراحی سایت بخواهیم تصویر کاربر را هنگام ثبت نام از وی دریافت نماییم و با شماره‌ی شناسه‌ی کاربری روی دیسک ذخیره کنیم. برای پیشگیری از ذخیره شدن اطلاعات بدون تصویر می‌توانیم ذخیره‌سازی اطلاعات کاربر را درون یک ترنزاکشن انجام دهیم، سپس تصویر را ذخیره کنیم و به پروفایل نسبت دهیم. اگر ذخیره‌سازی تصویر با مشکل مواجه شد، کافی است ترنزاکشن را به عقب برگردانیم تا تمامی اطلاعات ذخیره شده از بین بروند و خطای لازم را به کاربر نشان دهیم.(منبع این پاراگراف rokaweb.ir)

بگذرید کمی بیشتر مسیله رو باز کنیم:

فرض کنید شما قصد پیاده سازی یک عملیات بانکی را دارید یا قصد دارید هنگام ایجاد هر کاربر یک حساب کاربری نیز برای آن ایجاد شود. اگر عملیات ایجاد حساب کاربری یا ایجاد کاربر  با شکست مواجه شود چه اتفاقی رخ خواهد داد؟

به کد زیر دقت کنید:

// Create Account
$newAcct = Account::create([
    'accountname' => Input::get('accountname'),
]);

// Create User
$newUser = User::create([
    'username' => Input::get('username'),
    'account_id' => $newAcct->id,
]);

 

در حالت ممکن دو اتفاق پیش آید:

حساب ( Account ) ایجاد نشود

 

اگر اکانت ایجاد نشود بدون شک account_id نیز برای ایجاد user وجود نخواهد داشت و این فرآیند شکست خواهد خورد. اما ما باید بررسی کنیم که اگر اکانت ایجاد شد سپس کاربر نیز ایجاد شود. که در کد بالا برای بررسی وجود اکانت کدی قرار داده نشده است.

 

کاربر (user) ایجاد نشود

حالت دوم زمانی رخ خواهد داد که اکانت ایجاد و کاربر ایجاد نشود- در این حالت ما اکانتی داریم که متعلق به هیچ کاربری نمی باشد و بنابراین در دیتابیس اطلاعاتی موجود می باشد که متعلق به هیچ کدام از کاربران نیست.

شما می توانید برای جلوگیری از رخ دادن هرکدام از حالت های بالا از transactions استفاده نمایید.

 

Database transactions شامل سه بخش می باشد:

1- Creating a transaction: اجازه دادن به دیتابیس برای استفاده از ترنزاکشن

2- Rolling back a transaction: زمانی که عملیات با موفقیت انجام نشده باشد. تمام تغییرات اعمال شده باید برگشت داده شود.

3- Committing a transaction: به این معنی می باشد که عملیات با موفقیت انجام و تایید شده اند.

 

 

Transactions in Laravel

اولین راه برای استفاده از ترنزاکشن در لاراول قرار دادن کئوری ها در میان کلوژر فانکشن DB::transaction() بصورت زیر می باشد:

DB::transaction(function()
{
    $newAcct = Account::create([
        'accountname' => Input::get('accountname')
    ]);

    $newUser = User::create([
        'username' => Input::get('username'),
        'account_id' => $newAcct->id,
    ]);
});

 

برای اینکه متوجه شوید که کد بالا چطور عملیات ما را ترنزاکشن میکند و در صورت موفق نبودن برگشت می دهد بهتر است به منبع کد نگاهی بیندازیم:

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

            // We'll simply execute the given callback within a try / catch block
            // and if we catch any exception we can rollback the transaction
            // so that none of the changes are persisted to the database.
            try
            {
                    $result = $callback($this);

                    $this->commit();
            }

            // If we catch an exception, we will roll back so nothing gets messed
            // up in the database. Then we'll re-throw the exception so it can
            // be handled how the developer sees fit for their applications.
            catch (\Exception $e)
            {
                    $this->rollBack();

                    throw $e;
            }

            return $result;
    }

 

همونطور که می بینید اگر خطایی رخ بده عملیات rollback اجرا خواهد شد 

با این حال شما نیز می توانید خودتان برای exception های شخصی و دلخواه خودتون رو هم ایجاد کنید. برای نمونه به کد زیر دقت کنید:

DB::transaction(function()
{
    $newAcct = Account::create([
        'accountname' => Input::get('accountname')
    ]);

    $newUser = User::create([
        'username' => Input::get('username'),
        'account_id' => $newAcct->id,
    ]);

    if( !$newUser )
    {
        throw new \Exception('User not created for account');
    }
});

 

 در اینجا گفتیم که اگر کاربر جدید ایجاد نشه یک Exception برگشت داده بشه.

 

البته باز هم میتونیم ترنزاکشن های خودمون رو شخصی سازی تر کنیم و حتی پیغام های دلخواه برای کاربرانمان نمایش بدیم. مثلا در کد زیر ما با استفاده از try این قابلیت رو ایجاد کردیم که اگر بخشی از کد اجرا نشد کاربر به روت خاصی ریدایرکت بشه:

try {
    // Validate, then create if valid
    $newAcct = Account::create( ['accountname' => Input::get('accountname')] );
} catch(ValidationException $e)
{
    // Back to form with errors
    return Redirect::to('/form')
        ->withErrors( $e->getErrors() )
        ->withInput();
}

try {
    // Validate, then create if valid
    $newUser = User::create([
        'username' => Input::get('username'),
        'account_id' => $newAcct->id
    ]);
} catch(ValidationException $e)
{
    // Back to form with errors
    return Redirect::to('/form')
        ->withErrors( $e->getErrors() )
        ->withInput();
}

 

اما کد بالا هم مشکل ما رو به درستی رفع نخواهد کرد! و در صورت عدم ایجاد user و بوجود اومدن خطا- حساب کاربری ایجاد شده باقی خواهد ماند و از دیتابیس حذف نخواهد شد. پس چاره چیه؟؟ 

در لاراول به راحتی می توانیم با استفاده از توابع دستی DB::beginTransaction(); - DB::rollBack(); - DB::commit(); عملیات ترنزاکشن رو بصورت دلخواه ایجاد نماییم. 

لاراول از این توابع به عنوان توابعی برای کنترل دستی عملیات های دیتابیس نام میبره که می تونید با استفاده از اونها بصورت دلخواه عملیات های خودتون رو ترنزاکشن کنید.

با استفاده از این توابع کد بالا را بصورت بهینه تر خواهیم نوشت:

 

DB::beginTransaction();

try {
    // Validate, then create if valid
    $newAcct = Account::create( ['accountname' => Input::get('accountname')] );
} catch(ValidationException $e)
{
    // Rollback and then redirect
    // back to form with errors
    DB::rollback();
    return Redirect::to('/form')
        ->withErrors( $e->getErrors() )
        ->withInput();
} catch(\Exception $e)
{
    DB::rollback();
    throw $e;
}

try {
    // Validate, then create if valid
    $newUser = User::create([
        'username' => Input::get('username'),
        'account_id' => $newAcct->id
    ]);
} catch(ValidationException $e)
{
    // Rollback and then redirect
    // back to form with errors
    DB::rollback();
    return Redirect::to('/form')
        ->withErrors( $e->getErrors() )
        ->withInput();
} catch(\Exception $e)
{
    DB::rollback();
    throw $e;
}

// If we reach here, then
// data is valid and working.
// Commit the queries!
DB::commit();

همونطور که می بینید در ابتدا با استفاده از DB::beginTransaction(); یک ترنزاکشن ایجاد کردیم و در انتها با استفاده از DB::commit(); در صورت موفق بودن عملیات آن را کامیت می کنیم. 

همچنین درصورت ایجاد خطا با استفاده از DB::rollback(); در بخش های catch  عملیات rollback انجام خواهد شد.

 

امیدوارم از این آموزش استفاده برده باشید.

درصورتی که سوالی یا پیشنهادی دارید از بخش نظرات ارسال کنید.

57 admin
نظرات

برای اطلاع از پاسخ به نظر شما می توانید ایمیل یا شماره موبایل خود را وارد نمایید. *

ایمیل و شماره موبایل شما کاملا مخفی خواهد ماند و در سایت نمایش داده نخواهد شد. *

پاسخ به نظر
اگر نظری برای این مطلب ارسال شد از طریق ایمیل مرا اطلاع بده!

هنوز برای این مطلب نظری ارسال نشده است!
0