سلام، بنده نیاز دارم تابعی اجرا بشه و مقادیری رو در دیتابیس تغییر بده و مقادیری رو هم اضافه کنه،
مشکلی برای اجرا نیست و زمان زیادی هم طول نمیکشه ولی وقتی بلافاصله بعد از اجرا اگر back زده بشه اجرای تابع نصف کاره میمونه و نتیجه نهایی اشتباه میشه. چطور میتونم اجرای تابع رو کنترل کنم و از اجرای کاملش مطمئن بشم
ممنون میشم راهنمایی بفرمایید
تعریفتون دقیقا از «روی هاست کار نمیکنه» چی هست؟ انتظار چه رفتاری دارید که خلافش انجام میشه؟
ضمنا مورد دوم اینکه برای استفاده از Transaction ها در لاراول یک روش دیگه هم وجود داره و اون هم با استفاده از دستورات زیر هست:
use Illuminate\Support\Facades\DB;
DB::beginTransaction();
با دستور بالا محدوده شروع Transaction رو معین مکنید. اگر در اواسط مشکلی بوجود اومد با دستور زیر rollback میکنید:
DB::rollBack();
و اگر تا آخرین خط کد رسید اون وقت بصورت دستی دستور commit رو به شکل زیر میدید تا همه کوئری ها با همدیگر اجرا شوند:
DB::commit();
یکبار با روش بالا تست کنید. شاید اوکی شد.
گرچه یک حدس دیگه هم دارم... مطمئن نیستم ولی تا جایی که میدونم وقتی یک ریکوئست ارسال شد و پردازشش در سمت سرور استارت خورد، عملا دیگه کاربر نمی تونه جلوش رو بگیره و stopش کنه و اون عملیات تا انتها انجام خواهند شد. حتی اگر در طول این مدت کاربر back زده باشه. اتفاقی که در این صورت می افته این هست که فقط response به کاربر نمی رسه ولی اصل اتفاق که در سمت سرور هست تا انتها انجام میشه. شاید به همین خاطر هست که Transaction با موفقیت commit میشه. چون هیچ مانعی براش بوجود نمیاد که خواسته باشه rollback کنه.
هر چقدر فکر میکنم مثالی هم خاطرم نمیاد که در سایتی کاربر با back زدن بتونه جلوی اجرای عملیات رو در سمت سرور بگیره. فقط با اینکار ارتباط خودش رو قطع می کنه و response بهش نمی رسه. به همین خاطر هم هست که در کارهای حساس مثل پرداخت و آزمون و ثبت نام و ... میگن به هیچ وجه از کلید back استفاده نکنید.
@ali.bayat آقای بیات خوشحال میشم نظرتون رو بشنوم. به نظرتون حدسم درسته و درست متوجه این قضیه شدم؟
این پروسه شامل ۲ تا کوئری میشه
شما برای اینکه اطمینان پیدا کنی که هر ۲ تا اجرا میشه باید از سیستم Transaction استفاده کنی
به این ترتیب اگر یکی از کوئری هات Fail هم بشه
سایر کوئری ها هم rollback میشند
DB::transaction(function(){
Model1::insert([]);
Model2::update([]);
});
به عبارت دیگه یا همش با هم اجرا میشه یا هیچکدوم اجرا نمیشه
@ali.bayat از سیستم transaction استفاده کردم اما بازم هنگام لود شدن صفحه اگر back زده بشه کامل اجرا نمیشه
راه دیگه ای وجود نداره؟
ممنون میشم راهنمایی بفرمایید
@milad @mhyeganeh @hesammousavi @saman1111 @Rp76 @nimageneral
هنگام لود شدن صفحه اگر back زده بشه
با این کار شما فرصت اجرای کامل این قطعه کد رو میگیری
و چون داری از transaction استفاده میکنی قاعدتا همه تغییرات rollback میشه
یه نکته جانبی:
کدت رو بررسی کردم. حداقل 5،6 جا foreach داری که داخلش کوئری ساخته و اجرا میشه
این کار اصلا بهینه نیست
اولا باعث میشه زمان اجرا و لود صفحه بالا بره
دوما برای یه پروژه کوچیک این زمان شاید قابل تحمل باشه اما وقتی سرور زیر بار باشه، اصلا خوب نیست
قبلش یه کوئری لاگ بگیر
ببین چند تا کوئری داره برای این یه تیکه کد اجرا میشه
@ali.bayat
تغییرات rollback نمیشه ؟
در حین لود back میزنم اما rollback نمیشه باید چیکار کنم ؟
اول اینکه کدتون یکسری ایرادهای نسبتا جدی داره. دنبال بهینه سازیش باشید در اولین فرصت.
دوما Transaction ها هم می تونه یک راهکار خوب باشه و معنی نداره در هیچ زمانی فقط بخشیش انجام شده باشه. معناش کلا این هست یا همه اش با هم و یا هیچ کدوم. اگر این اتفاق نمی افته در پیاده سازیش اشتباه کردید.
و اما اگر اجرای فرایندتون زمان بر هست، یک پیشنهاد دیگه این هست که از Queue و job در لاراول استفاده کنید. به این شکل که با کلیک بروی لینک مورد نظر صرفا job ساخته میشه و به صف اضافه بشه. و در همین جا پاسخ رو برگردونید. بدلیل زمان کمی که برای این بخش از کار نیاز هست معمولا فرصت اینکه کاربر بخواد back بزنه وجود نداره اصلا و خیلی سریع اتفاق می افته. در صفحه بعد به کاربر یک پیغام نمایش داده میشه مثل «در حال پردازش...»
وقتی job به صف اضافه شد، پشت صحنه worker ها به سراغش میرن و عملیات رو تکمیل میکنند. اگر نیاز بود میتونید با ajax هر چند ثانیه یکبار درخواست بزنید که هر وقت عملیات تکمیل شده بود، به کاربر اطلاع بدید. یا از وب سوکت استفاده کنید تا ارتباط دو طرفه برقرار بشه.
@mhyeganeh حتما بهینه سازی میکنم فقط اینکه
روی لوکال مشکلی نداره پس نمیتونه پیاده سازیش مشکل داشته باشه روی هاست مشکل پیدا میکنه و کار نمیکنه
نحوه پیاده سازی هم داخل کد بالا مشخص هست
راهی نداره همین transaction کارکنه ؟
روی لوکال بدون استفاده از transaction هم درست کار میکنه و مشکلی نداره
روی هاست داخل تابع از کد زیر استفاده میکنم اما با این که اجرای تابع نیمه کاره انجام میشه متد rollback انجام نمیشه
اروری هم نمیده
ممنون میشم اگه راهنمایی کنید
DB::transaction(function (){
foreach ($tests1 as $test) {
$t1 = Model1::where('id',$test->id)->first();
$data['value'] = 100;
$t->update($data);
}
foreach ($tests2 as $test) {
$t2 = Model2::where('id',$test->id)->first();
$data['value'] = 100;
$t2->update($data);
}
});
تعریفتون دقیقا از «روی هاست کار نمیکنه» چی هست؟ انتظار چه رفتاری دارید که خلافش انجام میشه؟
ضمنا مورد دوم اینکه برای استفاده از Transaction ها در لاراول یک روش دیگه هم وجود داره و اون هم با استفاده از دستورات زیر هست:
use Illuminate\Support\Facades\DB;
DB::beginTransaction();
با دستور بالا محدوده شروع Transaction رو معین مکنید. اگر در اواسط مشکلی بوجود اومد با دستور زیر rollback میکنید:
DB::rollBack();
و اگر تا آخرین خط کد رسید اون وقت بصورت دستی دستور commit رو به شکل زیر میدید تا همه کوئری ها با همدیگر اجرا شوند:
DB::commit();
یکبار با روش بالا تست کنید. شاید اوکی شد.
گرچه یک حدس دیگه هم دارم... مطمئن نیستم ولی تا جایی که میدونم وقتی یک ریکوئست ارسال شد و پردازشش در سمت سرور استارت خورد، عملا دیگه کاربر نمی تونه جلوش رو بگیره و stopش کنه و اون عملیات تا انتها انجام خواهند شد. حتی اگر در طول این مدت کاربر back زده باشه. اتفاقی که در این صورت می افته این هست که فقط response به کاربر نمی رسه ولی اصل اتفاق که در سمت سرور هست تا انتها انجام میشه. شاید به همین خاطر هست که Transaction با موفقیت commit میشه. چون هیچ مانعی براش بوجود نمیاد که خواسته باشه rollback کنه.
هر چقدر فکر میکنم مثالی هم خاطرم نمیاد که در سایتی کاربر با back زدن بتونه جلوی اجرای عملیات رو در سمت سرور بگیره. فقط با اینکار ارتباط خودش رو قطع می کنه و response بهش نمی رسه. به همین خاطر هم هست که در کارهای حساس مثل پرداخت و آزمون و ثبت نام و ... میگن به هیچ وجه از کلید back استفاده نکنید.
@ali.bayat آقای بیات خوشحال میشم نظرتون رو بشنوم. به نظرتون حدسم درسته و درست متوجه این قضیه شدم؟
به نظر من هم پروسه ای که سمت سرور استارت میخوره، معمولا ادامه پیدا میکنه
نهایتا کاربره که با اجرای یه درخواست دیگه و یا استفاده از back خودش باعث میشه response رو نبینه.
صحبتتون منطقی به نظر میرسه
آیا مایل به ارسال نوتیفیکیشن و اخبار از طرف راکت هستید ؟