PDA

View Full Version : لازم بودن یا نبودن قفل , مسئله این است !



intel_amd
دوشنبه 21 مهر 1393, 12:26 عصر
بعد از اینکه با مسئله ای برخورد کردم که برای نامطمئن بودن سرنوشت پردازش حس نیاز به قفل به برنامه نویس دست میداد رفتم مباحث قفل دنبال کردم اما الان جاهائی دیدم گفته شده حتی قفل نیاز نیست و dbms خودش مدیریت میکنه و فلان و بهمان ... حالا از دوستان میخام مسئله زیرو ببینن قفل لازم داره بالاخره یا نه
تعداد بسیار زیادی یوزر میتونن عمل زیرو همزمان به سمت سرور درخواست بدن
پردازش این است : سلکت کن ببین اگر فلان رکورد در جدول موجود است اول این رکورد را پاک کن و سپس تغییراتی در مقادیر فیلدهای یک جدول دیگر اعمال کن و یک رکورد در جدول دیگری هم ایجاد کن
حالا مسئله ای که اول به ذهن میرسه اینه که چند درخواست میرسن و بر طبق اختلاف زمان های بسیار کوچیک بینشون به صف میشن و اولین درخواست سلکت میکنه میبینه فلان رکورد وجود داره و تا میاد این رکوردو پاک کنه طی این زمان که در حال گذره رکورد بعدی از صف میاد سلکت میکنه اینم میبینه بازم اون رکورد وجود داره و حالا درخواست اولی این رکورد پاک میکنه اما درخواست دومی چیزی نیست پاک کنه , پس بقیه پردازش با خطای پاک نشدن رکورد ادامه پیدا نمیکنه و قفل نمیخاد , این درست و دقیقه؟


صف ورود درخواست ها

درخواست 4
درخواست 3
درخواست 2
درخواست 1


سلکت درخواست 4
سلکت درخواست 3
سلکت درخواست 2
سلکت درخواست 1



پاک کردن رکورد توسط درخواست 4 انجام نمیشه
پاک کردن رکورد توسط درخواست 3 انجام نمیشه
پاک کردن رکورد توسط درخواست 2 انجام نمیشه
پاک کردن رکورد توسط درخواست 1

Unique
دوشنبه 21 مهر 1393, 14:59 عصر
راستش مثالتون را خوب مطرح نکردین و بهتره یک مثال ملموس تر بزنین.

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

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

به طور کلی هر جا تداخل چند نفر در یک فرایند باعث بروز مشکل در محاسبات و غیره بشه نیاز به قفل کردن جدول هست مگر اینکه این فرآیند مختص به یک کاربر خاص باشه و تاثیری روی بقیه نگذاره.

eshpilen
دوشنبه 21 مهر 1393, 15:50 عصر
درخواست اولی این رکورد پاک میکنه اما درخواست دومی چیزی نیست پاک کنه , پس بقیه پردازش با خطای پاک نشدن رکورد ادامه پیدا نمیکنه
کدوم خطای پاک نشدن رکورد؟
دستور delete در صورت پیدا نشدن رکوردی با شرایط مورد نظر، خطا نمیده. فقط از روی affetcted rows میتونید بفهمید که عملا رکوردی delete شده یا نه. ضمنا حتی روی اینم حساب نکنید، یعنی ممکنه موقعی که درخواست دوم هم میاد پاک کنه رکورد مورد نظر هنوز توسط درخواست قبلی دلیت نشده باشه!
ترتیب اجرای کوئری های درخواستها هیچ تضمینی نداره. یعنی اینکه یک درخواستی زودتر اومده و کوئری اول اون زودتر از درخواست دوم اجرا شده دلیل نمیشه بگیم که حتما کوئری دومش هم زودتر از کوئری دوم درخواست دوم اجرا خواهد شد.

نتیجه میگیریم که شما به قفل نیاز دارید. البته این بستگی به اینم داره که آیا اینطور موارد در برنامهء شما مشکل جدی ایجاد بکنن یا نه. یعنی اگر دوتا کوئری اینطوری لابلای هم اجرا بشن مشکلی در منطق برنامهء شما ایجاد بشه یا نه. این بستگی به الگوریتم و جزییاتش داره. در مورد شما بنظر میاد که نیاز باشه، چون میگید که «سپس تغییراتی در مقادیر فیلدهای یک جدول دیگر اعمال کن و یک رکورد در جدول دیگری هم ایجاد کن» و بنظر نمیاد که مقادیر و رکوردی که دو درخواست ایجاد میکنن با هم یکسان باشه.

حالا برای برنامتون چه نوع قفلی رو چه وقت و کجاها بذارید خودش باز مطلب دیگریست. اینم باز بستگی به جزییات دیگر برنامهء شما هم داره. اما اگر همینطور بصورت کلی و ساده ترین شکل رو بخوایم بگیم، فکر میکنم باید همون اول قبل از سلکت کردن یک قفل write روی جدول بگیرید و تا پایان عملیات نگهش دارید. البته اگر اون کورد خاص در جدول موجود نبود باید قفل رو بلافاصله آزاد کنید، ولی اگر موجود بود باید تا پایان عملیات هایی که گفتید نگهش دارید.

حالا باز گفتم که اینکه من گفتم خیلی کلی و ساده ترین ولی احتمالا غیربهینه ترین روشش بود. برای اینکه ببینید آیا لازمه و میشه و روش قفل بهینه تری رو طراحی کنید، کار خودتونه بطور معمول چون باید تمام برنامه و الگوریتم و جزییاتش رو دونست. این واسه خودش داستانیه! البته اگر برنامتون ترافیک سنگینی روی این جدولها/عملیات نداره، نیازی نیست نگران باشید و میتونید از ساده ترین و کلی ترین روش قفل کردن استفاده کنید و بزنید کل جدول یا جداول مربوطه رو قفل کنید!
ولی یوقت هست مثلا میگید در این مدت که این عملیات میخواد انجام بشه چرا درخواست دیگری که به این عملیات مربوط نیست میاد و میخواد از اون جدول بخونه یا حتی رکورد جداگانه ای که ربطی به این قضایا نداره توش بنویسه بلاک بشه، اونوقت اونم معمولا راههایی داره، ولی بطور معمول حجم و پیچیدگی برنامه رو افزایش میده و بنابراین تا وقتی که بنظرتون عملا خیلی مفید یا ضروریه اصراری نیست که انجامش بدید. بنظر بنده برنامه نویس باسواد و توانا اونی نیست که همه جا به هر قیمتی مته به خشخاش بذاره و سریعترین و پیشرفته ترین کد رو بنویسه، بلکه اونیه که این توانایی رو داشته باشه اما فقط جاهایی که واقعا نیازه یا فوایدش به هزینه هاش (هزینه ها: افزایش حجم و پیچیدگی کد و مصرف بیشتر وقت و انرژی ارزشمند برنامه نویس و کاهش خوانایی و قابلیت نگهداری برنامه) می ارزه این کار رو بکنه. امروزه روز وقت و انرژیت رو بذاری یه چیزی جدید یاد بگیری و دانش و توانایی های خودت رو افزایش بدی خیلی بهتره تا اینکه بخوای برنامه ای رو که همینطوریش هم به خوبی کار شما رو راه میندازه بهینه تر کنی! مثلا همین که شما سر این مسئله گیج شدی نشون میده هنوز نیاز داری بری و در زمینهء همزمانی و تداخل کوئری ها و روشهای قفل مطالعه و تحقیق و فکر و تحلیل و تست بکنی و به این مبحث مسلط تر بشی. این برای شما از بهینه سازی های وسواسی کاربردی تره. بالاخره یه چیزی رو بخوای بهینه بکنی اول باید به خود اون قضیه و الگوریتم هم تسلط داشته باشی که بدونی چطور بهینه کنی که هم هدف اولیه و اصلی رو خراب نکنی و هم بهینه سازیت بهینه باشه!

eshpilen
دوشنبه 21 مهر 1393, 16:25 عصر
البته اگر از جدولی استفاده میکنید که ترنزکشن ساپورت میکنه، که به احتمال زیاد اینطوره، میتونید همهء اون کوئری های مربوط رو توی یک ترنزکشن بذارید، و به کوئری اول (سلکت) عبارت FOR UPDATE رو اضافه کنید.
در این مقاله راجع به این روش توضیح دادم: http://hamidreza-mz2.tk/?p=940
خوبی این روش اینه که فقط کوئری هایی رو که بوسیله دستور سلکت خونده میشن قفل میکنه و کل جدول قفل نمیشه. یعنی قفل در سطح رکورد است. و این روش احتمالا بهینه ترین روش برای بیشتر برنامه های اینچنینی است.
اما باز اینم لزوما اینطور نیست که بگیم همه جا روش درستیه. همونطور که گفتم این دیگه کار برنامه نویسه و به تمام جزییات برنامه بستگی داره و کس دیگه نمیتونه همینطوری یه چیز کلی و مطلق دربارش بگه و فرمول واحدی برای همه جا و همه شرایطی بده. مثلا یک چیزی که بنظر من میرسه اینه که شاید در برنامهء شما امکان داشته باشه که یکی از همون نوع رکوردهایی که کوئری اول شما سلکت میکنه در این مدت به جدول اول اضافه بشه، و طبیعتا چون اون رکورد جدید توسط کوئری اول شما خونده نشده و بنابراین قفل نشده بوده، کوئری درخواست بعدی میتونه اون رو بدون اینکه پشت قفل منتظر بمونه بخونه، و اونوقت میره سروقت بقیهء عملیات مربوطه بدون اینکه منتظر پایان عملیات های درخواست قبلی بشه و این ممکنه در برنامهء شما باز مشکل تداخل ایجاد کنه. گفتم که بستگی به جزییات داره و فقط خود شما تمام جزییات برنامتون رو میدونید و فقط شما حاضرید اینقدر روش حوصله و وقت و انرژی صرف کنید که تمام این موارد رو تحلیل و بررسی کنید.

کلا فکر میکنم استفاده از این روش (FOR UPDATE) مال وقتیه که میخواید تغییرات بعدی رو روی همون رکوردهایی که خوندید انجام بدید. ولی شما میخواید تغییرات رو روی جدولها و رکوردهای دیگری انجام بدید.

intel_amd
دوشنبه 21 مهر 1393, 16:28 عصر
کدوم خطای پاک نشدن رکورد؟
دستور delete در صورت پیدا نشدن رکوردی با شرایط مورد نظر، خطا نمیده. فقط از روی affetcted rows میتونید بفهمید که عملا رکوردی delete شده یا نه. ضمنا حتی روی اینم حساب نکنید، یعنی ممکنه موقعی که درخواست دوم هم میاد پاک کنه رکورد مورد نظر هنوز توسط درخواست قبلی دلیت نشده باشه!
ترتیب اجرای کوئری های درخواستها هیچ تضمینی نداره. یعنی اینکه یک درخواستی زودتر اومده و کوئری اول اون زودتر از درخواست دوم اجرا شده دلیل نمیشه بگیم که حتما کوئری دومش هم زودتر از کوئری دوم درخواست دوم اجرا خواهد شد.

نتیجه میگیریم که شما به قفل نیاز دارید. البته این بستگی به اینم داره که آیا اینطور موارد در برنامهء شما مشکل جدی ایجاد بکنن یا نه. یعنی اگر دوتا کوئری اینطوری لابلای هم اجرا بشن مشکلی در منطق برنامهء شما ایجاد بشه یا نه. این بستگی به الگوریتم و جزییاتش داره. در مورد شما بنظر میاد که نیاز باشه، چون میگید که «سپس تغییراتی در مقادیر فیلدهای یک جدول دیگر اعمال کن و یک رکورد در جدول دیگری هم ایجاد کن» و بنظر نمیاد که مقادیر و رکوردی که دو درخواست ایجاد میکنن با هم یکسان باشه.

حالا برای برنامتون چه نوع قفلی رو چه وقت و کجاها بذارید خودش باز مطلب دیگریست. اینم باز بستگی به جزییات دیگر برنامهء شما هم داره. اما اگر همینطور بصورت کلی و ساده ترین شکل رو بخوایم بگیم، فکر میکنم باید همون اول قبل از سلکت کردن یک قفل write روی جدول بگیرید و تا پایان عملیات نگهش دارید. البته اگر اون کورد خاص در جدول موجود نبود باید قفل رو بلافاصله آزاد کنید، ولی اگر موجود بود باید تا پایان عملیات هایی که گفتید نگهش دارید.

حالا باز گفتم که اینکه من گفتم خیلی کلی و ساده ترین ولی احتمالا غیربهینه ترین روشش بود. برای اینکه ببینید آیا لازمه و میشه و روش قفل بهینه تری رو طراحی کنید، کار خودتونه بطور معمول چون باید تمام برنامه و الگوریتم و جزییاتش رو دونست. این واسه خودش داستانیه! البته اگر برنامتون ترافیک سنگینی روی این جدولها/عملیات نداره، نیازی نیست نگران باشید و میتونید از ساده ترین و کلی ترین روش قفل کردن استفاده کنید و بزنید کل جدول یا جداول مربوطه رو قفل کنید!
ولی یوقت هست مثلا میگید در این مدت که این عملیات میخواد انجام بشه چرا درخواست دیگری که به این عملیات مربوط نیست میاد و میخواد از اون جدول بخونه یا حتی رکورد جداگانه ای که ربطی به این قضایا نداره توش بنویسه بلاک بشه، اونوقت اونم معمولا راههایی داره، ولی بطور معمول حجم و پیچیدگی برنامه رو افزایش میده و بنابراین تا وقتی که بنظرتون عملا خیلی مفید یا ضروریه اصراری نیست که انجامش بدید. بنظر بنده برنامه نویس باسواد و توانا اونی نیست که همه جا به هر قیمتی مته به خشخاش بذاره و سریعترین و پیشرفته ترین کد رو بنویسه، بلکه اونیه که این توانایی رو داشته باشه اما فقط جاهایی که واقعا نیازه یا فوایدش به هزینه هاش (هزینه ها: افزایش حجم و پیچیدگی کد و مصرف بیشتر وقت و انرژی ارزشمند برنامه نویس و کاهش خوانایی و قابلیت نگهداری برنامه) می ارزه این کار رو بکنه. امروزه روز وقت و انرژیت رو بذاری یه چیزی جدید یاد بگیری و دانش و توانایی های خودت رو افزایش بدی خیلی بهتره تا اینکه بخوای برنامه ای رو که همینطوریش هم به خوبی کار شما رو راه میندازه بهینه تر کنی! مثلا همین که شما سر این مسئله گیج شدی نشون میده هنوز نیاز داری بری و در زمینهء همزمانی و تداخل کوئری ها و روشهای قفل مطالعه و تحقیق و فکر و تحلیل و تست بکنی و به این مبحث مسلط تر بشی. این برای شما از بهینه سازی های وسواسی کاربردی تره. بالاخره یه چیزی رو بخوای بهینه بکنی اول باید به خود اون قضیه و الگوریتم هم تسلط داشته باشی که بدونی چطور بهینه کنی که هم هدف اولیه و اصلی رو خراب نکنی و هم بهینه سازیت بهینه باشه!

در مورد پاراگراف اولتون دقیقا روی خطا دادن دلیت حساب کرده بودم که اگر خطا نمیده و یا کوئری های درخواست ها الزاما ترتیبی نیستند پس قفل لازمه
و در مورد پاراگراف دوم عملیات ادامه پردازش همانطور که گفتین دقیقا حیاتی هستند
در مورد پاراگراف سوم همین حالتی که گفتین مد نظرمه که در تاپیک زیر بیشتر دنبالش میکنم
http://barnamenevis.org/showthread.php?469580-کار-نکردن-قفل-!&p=2104640#post2104640


برای مثالی دیگر در ادامه کار که حتمی نیاز به قفل دارم مثال زیرو میتونم عنوان کنم :
در موقع ثبت نام یوزر ها لازمه به هر یوزر 2 عدد بین 0-100,000 داده شه که هیچ یوزری نباید این 2 عددشون باهم یکسان باشد
یعنی در هنگام کلیک بر روی دکمه ثبت نام باید اول سلکت شه 2 عدد رندوم و اگر در جدول نبود رکورد یوزر با این 2 عدد در جدول درج گردد در غیر این صورت این مرحله تا گرفتن جواب تکرار می شود و این پردازش باید در قفل انجام شود تا در هنگامی که 2 عدد یونیک پیدا شد و در حال ادامه درج رکورد یوزر با این 2 عدد است کاربر دیگری با این 2 عدد که هنوز در جدول وجود ندارد و یونیک هستند درج نشود

intel_amd
دوشنبه 21 مهر 1393, 18:17 عصر
مشکلات مربوط به قفلم حل شدن از دوستانی که در تاپیک های مختلفی که داشتیم در این باره یاری دادند تشکر میکنم