مهدی
1 سال پیش توسط مهدی مطرح شد
2 پاسخ

تراکنش به عقب باز نمی گردد

سلام دوستان
من میخوام توی لاراول از تراکنش ها استفاده کنم و در صورت پرتاب شدن یک استثنا در یکی از خطوط فانکش تراکنش رو به عقب برگردونم و این کار به راحتی انجام میشه ولی وقتی که استثنا در خارج از کنترلر رخ می ده، تراکنش به عقب بر نمی گرده

کدهای RegisterController :

use Illuminate\Support\Facades\DB;

class RegisterController extends Controller
{
    use AuthenticationTrait;

    public function register(RegisterRequest $request)
    {

       DB::beginTransaction();

        try {

            # Collect data from request
            $dataCollect = $this->collectDataFromRequest($request);

            # Create a new user
            $this->createUser($dataCollect);

            # Find ReferrerID from the request by invitation code
            $referrerId = $this->findRefererIdFromRequest($request);

            # Put ReferrerId into the user profile
            $this->putReferrerId($referrerId);

            DB::commit();

            # Return success response
            return response()->json($this->registerSuccessResponse());
        } catch (\Exception $ex) {
            DB::rollBack();
            return response()->json(['status' => false, 'message' => $ex->getMessage()], 422);
        }
    }
}

کدهای AuthenticationTrait :

trait AuthenticationTrait
{

    protected function collectDataFromRequest($request)
    {
        try {
            return collect($request->only([
                'name', 'email', 'password', 'country_id', 'language_id'
            ]));
        } catch (\Throwable $th) {
            throw new CustomException(__("The system is unable to collect input data."));
        }
    }

    protected function createUser($dataCollect)
    {
        try {

            # Generate hashed password
            $hashedPassword = bcrypt($dataCollect->get('password'));
            $dataCollect->put('password', $hashedPassword);

            # Create a new user
            $user = $this->userRepository->create($dataCollect->toArray());

        } catch (\Exception $th) {
            throw new CustomException(__('Sorry! The system is unable to create a new user account.'));
        }
    }

    protected function findRefererIdFromRequest($request)
    {
        throw new CustomException(__("The invitation code is invalid."));
    }

    protected function putReferrerId($referrerId)
    {
        # Update user profile and put referrerId into the user profile
    }

    // Other funtions ... 

}

اون متدهایی هم که داخل متد register کال زدم توی یک trait پیاده سازی شدن و همشونم داخل try catch هستن تا اگه نتونستن کار خودشونو بدرستی انجام بدن یه استثنا پرتاب کنن و اینجا داخل کنترلر هم دوباره از try catch استفاده کردم که اگه فانکشن های داخل trait خطا دادن اینجا Rollback اتفاق بیفته ولی نمی افته

انگار لاراول فقط زمانی رول بک انجام میده که تمامی پیاده سازی ها درون همون فانکشن register انجام بشه نه خارج از اون یا اینکه فقط اجازه میده از مدل ها یا کوئری بیلدر درون خود متد register استفاده کنیم نه بیرون از این متد
نمیدونم کلا منطقش چی هست و چرا وقتی فانکشنی که داخل یه کلاس دیگه نوشته شده و توش با الگونت در دیتابیس رکوردی ایجاد میکنیم و توی کنترلر اون فانکش رو کال میزنیم رو نمیتونه موقع خطا رول بک کنه
من توی نمونه کدی که بالا قرار دادم توی یکی از فانکشن هاش (findRefererIdFromRequest) عمدا اکسپشن پرتاب کردم تا داخل کنترلر و متد register بخش cache اجرا بشه و فرایند Rollback اتفاق بیفته ولی رول بک نمیشه و یوزر همچنان توی دیتابیس موجود هست.

نکته : من برای ایجاد کاربر در داخل AuthenticationTrait.php از کلاس دیگه ای استفاده کردم (لایه داده) که اسمشو گذاشتم UserRepository که داخلش متد create رو کال میزنم و کار خاصی اونجا انجام نمیدم و اونجا هم از همون الگوئنت لاراول استفاده کردم و متد create رو کال زدم.

کلاس UserRepository :

class UserRepository
{

    public Model $model;

    public function setModel(Model $model)
    {
        $this->model = $model;
        return $this;
    }

    public function create(array $data , User $user)
    {
        try {
            $this->setModel($user);
            return $this->model->create($data);
        } catch (\Throwable $th) {
            throw new CustomException(__("Sorry! The system is unable to create a new user account."));
        }
    }
}

میشه راهنمایی کنید ؟
ممنون میشم


ثبت پرسش جدید
Armia Armia
@armiaevil 1 سال پیش آپدیت شد
0

دو راه داری که دومیش مطعن نیستم جواب میده یا نه
یک: توی ساب فانکشن هات باز از DB::beginTransaction(); استفاده کنی به همراه try catch و...
دو: از closureاستفاده کنی

try{
    DB::transaction(function() {
        Your code ...
    }
}catch(\Exception $e){
    dd($e);
}

دقت کن که انجین دیتابیست روی InnoDB ست شده باشه متونی از داخل فولدر config فایل database بررسی کنی


مهدی
تخصص : توسعه دهنده
@mehdi539 1 سال پیش آپدیت شد
0

حل شد، ممنون🙏

بله انجین MyISAM فعال بوده و دقیقا مشکل به همین موضوع بر میگرده و هیچ ارتباطی هم به اجرای کوئری ها در صفحات مختلف نداشته
با انجین InnoDB تست کردم اوکی شد.
ممنون از توجهتون
اصلا حواسم نبود به اینکه انجین MyISAM اساسا از transaction ها پشتیبانی نمیکنه و نمی شه از commit یا rollback استفاده کرد.

ولی با توجه به داده های زیادی که در دیتابیس داریم و تعداد زیاد Reads ترجیح میدیم از MyISAM استفاده کنیم چون واقعا سرعت خواندن اطلاعات در MyISAM خیلی بیشتره
حالا راه حلی وجود داره که بشه از تراکنش ها برای انجین MyISAM استفاده کرد ؟


برای ارسال پاسخ لازم است وارد شده یا ثبت‌نام کنید

ورود یا ثبت‌نام