PDA

View Full Version : کار نکردن قفل !



intel_amd
پنج شنبه 27 شهریور 1393, 00:26 صبح
کد زیرو در نظر داشته باشید :


<?php
$con = mysql_connect("localhost", "root", "root");
mysql_select_db("test", $con);


mysql_query("LOCK TABLES us READ");


$result = mysql_query("SELECT * FROM us WHERE id=342", $con);
mysql_data_seek($result,0);
$row = mysql_fetch_array($result);
$op =$row['name'];


sleep(40);
echo $op;


mysql_query("UNLOCK TABLES;");


?>


این کدو نوشتم و از 2 مرورگر مجزا اجراش کردم و جالبه که تقریبا همزمان بعد از گذشت آن 40 ثانیه داخل 2 مرورگر reza که خروجی کد بالا باشه چاپ شد
در صورتی که اگر قفل کار می کرد 100% یکی از مرورگرها اول وارد قفل می شد و دیگری برای 40 ثانیه پشت در می ماند تا قبلی تمام شود و آن وارد می شد و بعد از 40 ثانیه هم خروجی خودش چاپ می شد , یعنی خروجی یکی از مرورگرها 40 ثانیه بعد از آن یکی باید چاپ می شد

eshpilen
پنج شنبه 27 شهریور 1393, 08:05 صبح
این حاصل یک اشتباه خیلی متداول و البته طبیعی است که بیشتر افراد دارن، حتی خیلی از حرفه ایها بعلت عدم مطالعهء دقیق و کامل مراجع فنی در این مورد، دچار این تصور غلط هستن! (که میتونه منجر به کدنویسی غلط و ایجاد باگ در برنامه هاشون بشه)

بنده قبلا یک مقاله در این مورد تهیه کردم چون یک نفر این مسئله رو در پیام خصوصی هم باهام مطرح کرد و جوابی که بهش دادم دیدم بهتره بصورت پابلیک و یک مقاله منتشر کنم: http://hamidreza-mz2.tk/?p=1168

خلاصه اینکه، قفل read فقط جلوی نوشتن رو میگیره و نه خواندن رو.
شما با ایجاد قفل read دارید میگید که میخواید از این جدول بخونید، نه اینکه هیچ کس دیگری اجازه نداره در این اثنا از این جدول بخونه.
ضمنا به قفل read با نام shared lock (قفل اشتراکی) هم اشاره میشه، چون همزمان چند پراسس میتونن روی یک جدول/رکورد قفل read داشته باشن. در این اثنا فقط درخواستها برای نوشتن یا گرفتن قفل write هست که باید منتظر بمونن تا تمام قفل های read روی اون جدول یا رکورد آزاد بشن.

بنابراین در قطعه کد شما، هر دو درخواست قفل read رو روی جدول میگیرن و همزمان دو تا قفل read روی جدول هست و درخواستهای خواندن هم هر دو میتونن بصورت موازی اجرا بشن.
حالا اگر READ رو به WRITE تغییر بدید، اونوقت نتیجه عوض میشه و مطابق انتظار شما درمیاد.

intel_amd
پنج شنبه 27 شهریور 1393, 09:39 صبح
چقد عجیب . چطور قفل رایت موجب عدم خواندن جدول شد و قفل رید موجب عدم نوشتن !

eshpilen
پنج شنبه 27 شهریور 1393, 10:28 صبح
خب دیگه ما اینیم :لبخند:
فهمیدن و حل چیزهای عجیب و غریب و ویژه تخصص ماست!
رضایت شما تعهد ماست :لبخندساده:
مهندس شهرکی باز بیا بگو اشپیلن سوادت اونقدری که فکر میکنی نیست :متعجب:
تازشم الان داشتم راجع به این موضوعات بیشتر (http://dba.stackexchange.com/questions/76939/is-it-possible-that-records-are-changed-while-a-read-query-is-still-executing) هم تحقیق و مطالعه میکردم. واقعا به اون سادگی نیست که بعضیا فکر میکنن. داستانها و نکته های متعدد و ظریفی داره. اینکه در چه مواردی و چطوری قفل کنیم خودش کلی اطلاعات و بینش میخواد. مثلا وقتی کوئریت داره فقط با یک رکورد کار میکنه، یا با چندتا، فرقش چیه، آیا باید قفل بکنی نکنی میشه نمیشه، با قفل چطوریه با ترنزکشن چطوری، داستان MyISAM در این مورد چیه داستان InnoDB چیه فرقشون چیه رفتار پیشفرضشون چیه، باید دقیقا تحقیق و بررسی کنی ببینی شاید در بعضی موارد خود DBMS داره بصورت خودکار اون چیزی رو که شما نگرانش هستی انجام میده که طبیعتا بهینه تر هم هست و شما نیای دوباره به شکل غیربهینه ای تکرارش کنی ... منکه اینقدر حرفه ایم و قبلا در این زمینه مطالعه کردم الان چندتا سوال و ابهام به ذهنم رسید در این مورد که هنوز از جوابشون مطمئن نیستم. حتی با اینکه الان تست عملی هم انجام دادم ولی بازم مطمئن نشدم چون ممکنه رفتار مشاهده شده دلایل دیگری داشته باشه یا گمراه کننده باشه، و این رفتار با گفته ها و منابع ظاهرا جور در نمیاد.

intel_amd
پنج شنبه 27 شهریور 1393, 11:08 صبح
الان تست کردم و یک چیز عجیب تر ! الان read_write گذاشتم بجای write که شامل جفتش بشه اما باز انگار قفل نیست !
یعنی با اینکه read هم به write اضافه کردم باید read قفل نوشتن اضافه میکرد که نه تنها این نشد بلکه قفل خواندن هم از write انداخت !
اینجور که من حس ششمم بهم میگه این write هم برای رید و هم برای رایت جدول را قفل میکنه و read فقط طوری جدول قفل میکنه که فقط میشه ازش read کرد

Unique
پنج شنبه 27 شهریور 1393, 14:27 عصر
دوست عزیز ما چیزی به نام read_write نداریم.

lock کردن جدول معمولا زمانی انجام میشه که نگران تغییر در اطلاعاتی هستیم که داریم روش فرایندی را انجام میدیم ! در شرایط غیر از این قفل کردن جدول یک کار بیهوده و اشتباهه !
در ضمن برای MyISAM و InnoDB تعاریف کمی متفاوت میشه.

اگه میخواین از lock کردن جداول استفاده کنید حتما این صفحه (http://dev.mysql.com/doc/refman/5.0/en/lock-tables.html) را مطالعه کنید.

intel_amd
پنج شنبه 27 شهریور 1393, 17:06 عصر
خوب من هم روی جدولی که دارم نیازه یوزرها تغییراتی انجام بدن که اگر همزمان انجام شه اشکال پیش میاد مثالشو داخل تاپیک دیگری زده بودم
نوع read_write هم وجود داره داخل سایت ها دیدم اما تا جائی که متوجه شدم این read و write همان مفهومیو داره که داخل پست قبل در خط آخرش نوشتم

از لینکتون هم ممنون حتما مطالعه میکنم

eshpilen
پنج شنبه 27 شهریور 1393, 18:18 عصر
الان read_write گذاشتم بجای write که شامل جفتش بشه اما باز انگار قفل نیست !
یعنی با اینکه read هم به write اضافه کردم باید read قفل نوشتن اضافه میکرد که نه تنها این نشد بلکه قفل خواندن هم از write انداخت !

گمون کنم در MySQL همچین قفلی نداشته باشیم :متفکر:
احتمالا بخاطر خطای سینتاکس کوئری Fail شده و در نتیجه قفلی هم ایجاد نشده.


اینجور که من حس ششمم بهم میگه این write هم برای رید و هم برای رایت جدول را قفل میکنه و read فقط طوری جدول قفل میکنه که فقط میشه ازش read کرد
وقتی قفل write میگیری داری میگی من میخوام یه چیزی بنویسم.
فرض کن مثلا چند نفر اختیار نوشتن یا ویرایش یک نامهء اداری رو در یک سیستمی دارن. یکی از این چند نفر شروع میکنه به نوشتن نامه، طبیعی است که تا نوشتن و ویرایش نامه خودش رو تموم نکرده نه کسی باید نامه ای رو که هنوز ناقصه (و ممکنه حتی جاهای نوشته شده اون هم تا پایان عملیات مجددا ویرایش بشه و تغییر کنه) بخونه و نه اینکه اون رو قبل از اینکه نفر قبلی کارش رو تموم کنه دستکاری/ویرایش کنه.
قفل write هم از نظر منطقی این رو ایجاب میکنه که دسترسی در طی مدت نوشتن انحصاری باشه، بخاطر همین یک اسم دیگرش exclusive lock است.

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

این مثال نامه البته شاید مثال خیلی مناسب و دقیقی هم نبود، ولی فقط یک مثال فرضی بود و خواستم کلیت مطلب رو روشن کنم.

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

intel_amd
پنج شنبه 27 شهریور 1393, 18:53 عصر
تشکر تعریف جامعی بود

intel_amd
جمعه 28 شهریور 1393, 00:40 صبح
بازهم رفتار غیر منتظره !
یک قفل گذاشتم و بینش کدی که میخواستم نوشتم اما جالب اینجاست که حتی به کدی که داخل قفل هم هست اجازه نوشتن نمیده !! دیگه زیادی قفله به پردازشی هم که میخوام تو تنهائی بنویسه هم اجازه نوشتن نمیده کلا درشو بسته:لبخند:

eshpilen
یک شنبه 30 شهریور 1393, 09:51 صبح
کد؟! .............

intel_amd
یک شنبه 30 شهریور 1393, 12:51 عصر
کافیه یک قفل بذارید و داخلش یک insert یک چیزی داخل جدول بریزید
کار نمیکنه اما وقتی قفل کامنت کنید کار میکنه

eshpilen
سه شنبه 01 مهر 1393, 08:27 صبح
کوئری ها رو باید روی همون کانکشنی ارسال کنی که باهاش قفل رو گرفتی.