PDA

View Full Version : ارسال id فرد ثبت نام کننده به صورت آنی



iraniancoder
چهارشنبه 30 فروردین 1391, 15:56 عصر
سلام
من می خواهم بدانم چگونه می توانم تا مثلا کاربری بنام حسین ثبت نام کرد همان لحظه بعد از insert کردن آن شخص در جدول mysql من بتوانم فیلد آی دی که primary key جدول من هست را برای او بفرستم
من خودم همچین کاری می کنم بعد از insert کردن
select id from users where name='hossein'
که به نظر من راهی غلط است چون ممکن است قبل از این کاربر فردی دیگر بنام حسین ثبت نام کرده باشد

همچنین فیلد id من auto incremental است
یا علی

MMSHFE
چهارشنبه 30 فروردین 1391, 16:02 عصر
if(mysql_affected_rows() > 0) {
echo mysql_insert_id();
}

راهنمای تابع mysql_insert_id (http://ir.php.net/manual/en/function.mysql-insert-id.php)
موفق باشید.

eshpilen
پنج شنبه 31 فروردین 1391, 11:17 صبح
از نظر اصولیش باید قبل از کوئری insert، جدول قفل بشه و بعد از mysql_insert_id قفل آزاد بشه. چون در بین این دو عملیات ممکنه رکورد دیگری توسط یک درخواست دیگر در جدول درج بشه و بنابراین mysql_insert_id مقدار id اون رکورد رو برمیگردونه (نه رکورد مورد نظر خودتون). هرچند احتمالش ممکنه خیلی کم باشه اما بهرحال امکان داره (ضمنا هرچی ترافیک سایت/بار سرور بیشتر باشه احتمالش بیشتر میشه).

MMSHFE
پنج شنبه 31 فروردین 1391, 11:38 صبح
درسته. من روش ساده رو گفتم ولی روشی که جناب eshpilen میگن مطمئنتر هست و خیالتون راحته وقتی دارین توی جدول مینویسید، درخواستهای همزمان بعدی توی صف نگه داشته میشن تا وقتی که خودتون قفل رو آزاد کنید.

iraniancoder
جمعه 01 اردیبهشت 1391, 10:24 صبح
سلام
چگونه قفل کنم و آزاد کنم؟
یا علی

eshpilen
جمعه 01 اردیبهشت 1391, 18:53 عصر
با این کوئری قفل کنید:

LOCK TABLES `table_name` WRITE
(بجای table_name نام جدول مورد نظر)
و با این کوئری تمام قفلهای کانکشن جاری آزاد میشن:

UNLOCK TABLES

البته قفل کردن روشهای دیگری هم داره که میتونن بهینه تر و البته پیچیده تر باشن. ولی فکر میکنم برای کار شما و بیشتر کارها/سایتهای دیگه همین کفایت میکنه و هیچ مشکلی نداره.

----------------------------------

روشهای دیگر قفل کردن میتونه استفاده از Advisory lock باشه که میشه برای انجین MyISAM هم ازش استفاده کرد و میتونیم باهاش در سطح رکورد یا عملیات خاص قفل کنیم، تا در مدت قفل عملیات دیگر بتونن انجام بشن یا رکوردهای دیگر خونده بشن.
ضمنا فکر میکنم استفاده از Transaction هم میتونه نیاز ما رو برطرف کنه، ولی استفاده از Transaction نیاز به یک انجین مثل InnoDB داره که از ترنزکشن پشتیبانی میکنه. میگم فکر میکنم چون خودم تاحالا در این مورد تحقیق و کار و تست خاصی نداشتم.
بهرصورت اینا اطلاعات تئوریک و سرنخ هایی بود که برای کامل و دقیق بودن مطلب گذاشتم. اگر متوجه نشدید مشکلی نداره!!

MMSHFE
جمعه 01 اردیبهشت 1391, 23:04 عصر
پیشنهاد میکنم از دستور زیر برای قفل کردن جدول استفاده کنید:
LOCK TABLES `table` LOW_PRIORITY WRITE
تا به درخواستهای Read بعدی اجازه بده از جدول بخونن و فقط تا وقتی که UNLOCK TABLES رو صدا نزدین، اجازه نده چیز دیگری توی جدول نوشته بشه چون در حالت عادی اولویت قفل WRITE بیشتر از READ هست و درنتیجه جدولی که قفل WRITE داره به درخواستهای READ هم اهمیت نمیده اما وقتی از LOW_PRIORITY استفاده میشه، فقط جلوی نوشتنها رو میگیره و اجازه خوندن میده. با این کار، اگه همزمان با نوشتن شما افراد دیگه بخوان از جدول اطلاعات رو بخونن، نیاز نیست توی صف انتظار قرار بگیرن تا قفل آزاد بشه.
موفق باشید.

eshpilen
شنبه 02 اردیبهشت 1391, 08:59 صبح
در بیشتر سناریوها و شرایط نیازی به استفاده از LOW_PRIORITY نیست و حتی اصولی هم نیست.
LOW_PRIORITY در کاربردها و شرایط خاص بدرد میخوره. بطور مثال جایی که عملیات Write روی دیتابیس خیلی زیاد باشه و این (ممکنه) باعث بشه درخواستهای Read برای مدت زمان بیش از حد بلاک بشن (ضمنا این مسئله در عمل فقط در شرایط ترافیک واقعا سنگین میتونه رخ بده).
ولی جایی که شما درخواست Write خیلی زیادی ندارید و بخصوص درخواستهای Read مداوم و زیاد هستن، اصلا نیازی به استفاده از LOW_PRIORITY نیست و حتی این کار میتونه اصولی نباشه، چون در چنین حالتی بعکس، درخواستهای Write ممکنه برای مدت قابل توجهی بلاک بشن.
بخاطر همین پیشفرض این دستور LOW_PRIORITY نیست و بعکس هست، چون در بیشتر سناریوها تعداد درخواستهای Read از درخواستهای Write خیلی بیشتره، و در چنین شرایطی استفاده از LOW_PRIORITY برای عملیات Write صحیح نیست.

اسم قفل که میاد معمولا افراد حساس میشن و فکر میکنن !Oh My God الان دیگه فاجعه شده! و اون قضیهء وسواس در بهینه سازی که تاحالا چندبار راجع بهش صحبت کردم کار خودش رو میکنه!!
این قفل ها واقعا در بیشتر کاربردها و شرایط هیچ مشکل مشهودی ایجاد نمیکنن. یک زمان بسیار کوتاهی هست که قفلی صورت میگیره و به سرعت هم آزاد میشه و تنها اگر ترافیک بسیار سنگین باشه و تازه تعداد درخواستهای Write نسبت به درخواستهای Read زیاد باشه ممکنه درخواستهای مختلف از نظر نوبت به شدت با هم درگیر بشن و زمانهای انتظار قابل توجه مشاهده بشه.

eshpilen
شنبه 02 اردیبهشت 1391, 09:25 صبح
تا به درخواستهای Read بعدی اجازه بده از جدول بخونن و فقط تا وقتی که UNLOCK TABLES رو صدا نزدین، اجازه نده چیز دیگری توی جدول نوشته بشه چون در حالت عادی اولویت قفل WRITE بیشتر از READ هست و درنتیجه جدولی که قفل WRITE داره به درخواستهای READ هم اهمیت نمیده اما وقتی از LOW_PRIORITY استفاده میشه، فقط جلوی نوشتنها رو میگیره و اجازه خوندن میده.

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

کاری که LOW_PRIORITY اینه که اگر همزمان چند درخواست برای قفل WRITE و قفل READ بر روی یک جدول در صف انتظار باشن، به قفل های READ اولویت بیشتری میده و موقعی که فرصت قفل کردن جدول پیش آمد، قفل های READ رو اعطا میکنه و درخواستها برای قفل های WRITE مجبورن تا وقتی که هیچ درخواستی برای قفل READ در صف انتظار باقی نمونده باشه منتظر باقی بمونن .

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

MMSHFE
شنبه 02 اردیبهشت 1391, 09:28 صبح
من هم صحبتهای شما رو کاملاً قبول دارم. فقط بعنوان یک نکته گفتم که اگه سایتشون در شرایطی هست که بیشتر عمل نوشتن انجام میده تا خوندن، نوشتن رو LOW_PRIORITY کنن تا کارهای خوندن که تعدادشون زیاد نیست، انجام بشن وگرنه خیلی از جاها اصلاً استفاده از LOCK نیاز نیست. چه برسه به اینکه بخوایم اولویت و... رو هم تعیین کنیم. البته اون قسمت از صحبت شما که به درگیرشدن ازنظر نوبت اشاره کردین خیلی بعید بنظر میرسه چون زمان درخواستها با دقت MicroSecond یعنی میلیونیم ثانیه توی صف قرار میگیره و درنتیجه احتمال ثبت دو درخواست بطور دقیقاً همزمان خیلی بعیده. درهرحال من هم تأکید میکنم تا جایی که واقعاً نیازی نیست، اینقدر طراحی خودمون رو نباید پیچیده کنیم. حتی اگه در شرایط خاصی این پیچیدگی ضروری باشه، با کمک شرطها باید کنترل کنیم که پیچیدگی مذکور (مثل قفل و...) فقط توی همون شرایط اعمال بشه نه همیشه.
موفق باشید.

eshpilen
شنبه 02 اردیبهشت 1391, 09:55 صبح
من هم صحبتهای شما رو کاملاً قبول دارم. فقط بعنوان یک نکته گفتم که اگه سایتشون در شرایطی هست که بیشتر عمل نوشتن انجام میده تا خوندن، نوشتن رو LOW_PRIORITY کنن تا کارهای خوندن که تعدادشون زیاد نیست، انجام بشن وگرنه خیلی از جاها اصلاً استفاده از LOCK نیاز نیست. چه برسه به اینکه بخوایم اولویت و... رو هم تعیین کنیم. البته اون قسمت از صحبت شما که به درگیرشدن ازنظر نوبت اشاره کردین خیلی بعید بنظر میرسه چون زمان درخواستها با دقت MicroSecond یعنی میلیونیم ثانیه توی صف قرار میگیره و درنتیجه احتمال ثبت دو درخواست بطور دقیقاً همزمان خیلی بعیده. درهرحال من هم تأکید میکنم تا جایی که واقعاً نیازی نیست، اینقدر طراحی خودمون رو نباید پیچیده کنیم. حتی اگه در شرایط خاصی این پیچیدگی ضروری باشه، با کمک شرطها باید کنترل کنیم که پیچیدگی مذکور (مثل قفل و...) فقط توی همون شرایط اعمال بشه نه همیشه.
موفق باشید.
قفل از نظر اصولیش در جایی که امکان تداخل وجود داره لازمه، چون کمال و دقت منطق و امنیت برنامه بهش وابسته است.
قفل پیچیدگی بیخودی که نیست. بخاطر صحت الگوریتم و امنیت برنامه است. نبود قفل، یک باگ در پیاده سازی است. ممکنه در بیشتر سایتها احتمال وقوع تداخل درخواستها خیلی کم باشه، اما بهرحال این ضعف یک باگ محسوب میشه که در مواردی میتونه موجب مشکل امنیتی هم بشه. فرضا حتی یک در صد هزار اگر امکان داشته باشه که برنامهء شما آیدی دو نفر رو به این خاطر با هم اشتباه کنه، احتمال کمی نداره که در طول عمر سایت/برنامه این قضیه یک یا چند بار رخ بده و یک نفر بجای یک نفر دیگه شناخته بشه. این باگ امنیتی نیست؟ در ترافیک های سنگین یا موقع پرباری سرور یا بخاطر ضعیف بودن اون هم احتمال وقوع چنین شرایطی خیلی بیشتر میشه که اصلا نباید دست کم گرفت.
ضمنا اگر کسی متوجه این ضعف بشه احتمال سوء استفاده ازش میتونه وجود داشته باشه.
بنده روی سیستم خودم یک برنامه ای رو با اسکنر امنیتی اسکن کردم، نتیجهء باگ عدم استفاده از قفل رو مشاهده کردم. البته اونی که دانش و بینش این مسائل رو نداره بعیده اصلا به این مسئله توجه کنه یا اگر هم توجه کنه نمیتونه علتش رو بفهمه (و در فروم برنامه نویسی هم مطرح کنه باید شانس بیاره یک نفر آدم آگاه حضور داشته باشه و این مورد بنظرش برسه و بهش بگه).

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

در هیچ برنامه ای نباید این ضعف وجود داشته باشه. اما در موارد امنیتی و ترافیک بالا اهمیت و احتمال وقوعش خیلی بیشتر میشه.

MMSHFE
شنبه 02 اردیبهشت 1391, 12:48 عصر
با عرض پوزش، چیزی که شما میگید اشتباهه...
من منظورم رو نتونستم بطور کامل برسونم. منظورم درخواستهای READ دیگری هست که صراحتاً قفل READ میگیرن. توی سایت خود MySQL هم این مطلب ذکر شده. موفق باشید.

eshpilen
چهارشنبه 27 اردیبهشت 1391, 12:39 عصر
از نظر اصولیش باید قبل از کوئری insert، جدول قفل بشه و بعد از mysql_insert_id قفل آزاد بشه. چون در بین این دو عملیات ممکنه رکورد دیگری توسط یک درخواست دیگر در جدول درج بشه و بنابراین mysql_insert_id مقدار id اون رکورد رو برمیگردونه (نه رکورد مورد نظر خودتون). هرچند احتمالش ممکنه خیلی کم باشه اما بهرحال امکان داره (ضمنا هرچی ترافیک سایت/بار سرور بیشتر باشه احتمالش بیشتر میشه).
این گفته ها رو اصلاح میکنم! اشتباه بود!!
ظاهرا برای استفاده از mysql_insert_id نیازی به قفل نیست.
چون تاجاییکه تست کردم، این تابع مقدار id آخرین کوئری درخواست جاری رو برمیگردونه. یعنی حتی اگر قبل از فراخوانی این تابع، کوئری های insert دیگری توسط درخواستهای دیگری اجرا بشن، این تابع id مربوط به آخرین کوئری درخواست جاری رو برمیگردونه و به کوئری درخواستهای دیگه یا id آخرین رکوردی که واقعا تاحالا در جدول درج شده کاری نداره.

masoud_tamizy
چهارشنبه 27 اردیبهشت 1391, 14:54 عصر
خب من از اساتید یک سوال دارم : اگه یه تراکنش ایجاد کنه و همه اون عملیات رو در اون تراکنش بنویسه ... چطور ؟

Unique
چهارشنبه 27 اردیبهشت 1391, 15:10 عصر
دوستان من یک مشکلی دارم اینجا که شاید از معلومات کم منه ! فکر نمیکنید mysql_insert_id اخرین increment value ی را که توسط link جاری ایجاد شده بر میگردونه ؟ من راستش از document خود php میگم :

Retrieves the ID generated for an AUTO_INCREMENT column by the previous query (usually INSERT).

در ضمن این تابع یک link میگیره که توضیحش اینه :

he MySQL connection. If the link identifier is not specified, the last link opened by mysql_connect() is assumed. If no such link is found, it will try to create one as if mysql_connect() was called with no arguments. If no connection is found or established, an E_WARNING level error is generated.

منظور من اینه که اگه شما توی اسکریپت که به وسیله کاربر x باز شده یک connection باز کردی و Insert کردی و mysql_insert_id گرفتی بعد از اون insert حالا لگه کاربران y,z هم در همون لحظه کذایی از همون اسکریپت insert گرفته باشند ! link هر اجرای اسکریپت اخرین ID خودش را بر میگرونه و تداخلی پیش نمیاد ! این موضوع منطقی هم نیست که مشکلی پیش بیاد و یک ضعف محسوب میشه ! حتی MSSQL SERVER هم برای دریافت آخرین ID دستوراتی برای scope یا table و ... داره !

لطفا اگه من اشتباه میکنم با معرفی یک Source قابل اعتماد یا تجربه طلایی خودتون منو راهنمایی کنین.

eshpilen
چهارشنبه 27 اردیبهشت 1391, 21:03 عصر
منظور من اینه که اگه شما توی اسکریپت که به وسیله کاربر x باز شده یک connection باز کردی و Insert کردی و mysql_insert_id گرفتی بعد از اون insert حالا لگه کاربران y,z هم در همون لحظه کذایی از همون اسکریپت insert گرفته باشند ! link هر اجرای اسکریپت اخرین ID خودش را بر میگرونه و تداخلی پیش نمیاد ! این موضوع منطقی هم نیست که مشکلی پیش بیاد و یک ضعف محسوب میشه ! حتی MSSQL SERVER هم برای دریافت آخرین ID دستوراتی برای scope یا table و ... داره !

خب منم تقریبا همینو گفتم دیگه. فقط خواستم بگم نیازی به قفل نیست، چون درخواستها یا کانکشن ها با هم تداخل نمیکنن در این تابع.
منتها بیشتر تست نکردم که جزییات بیشتری بدم.
ضمنا با mysql_pconnect هم تست کردم که بازم نتیجه یکی بود. یعنی هر درخواست id مربوط به خودش رو برمیگردونه، با اینکه کانکشن ظاهرا باید Share بین باشه دو درخواست بخاطر استفاده از mysql_pconnect. حتما یه مشخصات دیگری هم هست یا شاید کانکشن خودش باز id ای چیزی داره که در هر درخواست تفاوت میکنه. شایدم یه چیزی در تست من مشکل داشته.

نفهمیدم مشکل شما کجاست.

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

Unique
پنج شنبه 28 اردیبهشت 1391, 00:25 صبح
این گفته ها رو اصلاح میکنم! اشتباه بود!!
منظور من این بالایی بود !

محمد شهرکی
چهارشنبه 17 خرداد 1391, 22:51 عصر
خب منم تقریبا همینو گفتم دیگه. فقط خواستم بگم نیازی به قفل نیست، .
دوستان بالاخره چی شد ، آیا باید از قفل استفاده کنیم . من برای گرفتن ID آخرین رکورد درج شده ، بعد از عمل درج ، جدول رو به صورت نزولی مرتب می کنم و با LIMIT یک سطر از جدول رو استخراج می کنم که دقیقا همان آخرین سطری که می خوام هستش ولی ترسی که دارم و همه تون هم اشاره کردین اینه که مبادا تو همون یه لحظه یه درج دیگه تو جدول اتفاق بیافته

Unique
پنج شنبه 18 خرداد 1391, 00:35 صبح
نیازی به دوباره select گرفتن و limit و order by نیست ، mysql_insert_id آخرین مقدار incremented value را بر میگردونه و نیازی هم به قفل کردن نیست.

eshpilen
پنج شنبه 18 خرداد 1391, 08:46 صبح
دوستان بالاخره چی شد ، آیا باید از قفل استفاده کنیم . من برای گرفتن ID آخرین رکورد درج شده ، بعد از عمل درج ، جدول رو به صورت نزولی مرتب می کنم و با LIMIT یک سطر از جدول رو استخراج می کنم که دقیقا همان آخرین سطری که می خوام هستش ولی ترسی که دارم و همه تون هم اشاره کردین اینه که مبادا تو همون یه لحظه یه درج دیگه تو جدول اتفاق بیافته
اگر میخوای ID آخرین رکوردی رو بگیری که توسط درخواست جاری درج شده، از mysql_insert_id استفاده کن؛ نیازی به قفل هم نیست. و از این روش Select و Limit خودت هم استفاده نکن!

ولی اگر میخوای ID آخرین رکورد جدول بطور کلی رو بگیری، بنظرم باید از همون Select و Limit و اینها استفاده کنی و احتمالا قفل هم لازم باشه.