# زبان های اسکریپتی > PHP > تاپیک های آموزشی و دنباله دار >  آموزش تراکنش کردن در MYSQL

## i-php-i

با سلام به دوستان عزیز

می تونم بگم این تاپیک اولین مقاله آموزشی من توی وب سایت برنامه نویس هست و امیدوارم مقاله مفیدی باشه

توی نرم افزارهایی که با پول  سروکار داره ممکنه حالتهایی پیش بیاد که نیاز  هست چندین کوئری بزنیم تا پول رو از حساب یک نفر کم کنیم و به حساب یه نفر  دیگه اضافه کنیم. در این حالت کوئری های ما به این صورت می تونه باشه:
UPDATE `user_mony` SET `mony`=mony-1500000 WHERE (`id`='A')
UPDATE `user_mony` SET `mony`=mony+1500000 WHERE (`id`='B')

در حالت عادی این کوئری ها درست کار می کنن ولی فرض کنید کوئری اول رو زدیم  و بعد سیستم خاموش شد! یا کوئری اول رو زدیم و قبل از کوئری دوم، کاربر B  از سیستم حذف بشه.

در هر دو حالت 150 هزار تومن به کاربر A ضرر زدیم! 

برای حل این مشکل سیستم ایزالاسیون Isolation Levels طراحی شده که از 4 سطح مختلف تشکیل می شه

لازم به ذکر هست که این سیستم روی جدول نوع InnoDB اجرا می شه و روی جدولهای نوع MyISAM کاربرد نداره.


*Read uncommitted*

در این حالت تراکنش در حال اجرا می تونه نتیجه تراکنش های انجام نشده رو  ببینه! نمی دونم چطور توضیحش بدم، فقط می تونم بگم بهتره این روش رو هیچوقت  استفاده نکنید!

*Read committed*

در این حالت تراکنش در حال اجرا می تونه نتیجه های تراکنش های انجام شده رو  ببینه و اطلاعاتی که به شما می ده واقعی هستن اما یه مشکل داره و اونم  اینکه ردیفهایی که در شرط تراکنش صدق می کنن رو قفل نمی کنه.

برای توضیح بهتر این مشکل این دو کوئری رو مثال می زنم که مدیر می خواد  تعداد کاربرهای طلبکار وب سایت خودش رو بدست بیاره (فرض می کنیم کلا 10  کاربر داریم که مدیر وب سایت باید به اونها پول پرداخت کنه)
SELECT * FROM `usertb` WHERE (`id`='ok')
SELECT * FROM `usertb` WHERE (`id`='ok')
بنظر می رسه که هر دوکوئری باید جواب یکسانی رو برگردونن اما فرض کنید بعد  از کوئری اول، یکی از کاربرها حساب کاربری خودش رو حذف می کنه و بعد کوئری  دوم اجرا می شه!

در این حالت نمی دونیم به مدیر بگیم 10 تا کاربر طلبکار داری یا 9 تا! و طبیعتا نمی تونیم مبلغ بدهی وب سایت رو دقیقا مشخص کنیم.

*Repeatable read*

این سطح از ایزولاسیون بر حل مشکل فوق ایجاد شده و در این سطح همه ردیف  هایی که در شرط کوئری ها صدق می کنن قفل می شن تا جلوی مشکلاتی که توضیح  داده شد گرفته بشه

در این حالت درسته که ردیفهایی که در شرط صدق می کنن قفل می شن ولی ممکنه   بعد از کوئری اول یه کاربر طلبکار جدید به لیست طلبکارها اضافه INSERT بشه و  چون تا حالا وجود نداشته طبیعتا نمی شد روش قفل گذاشت!

به همین دلیل کوئری دوم طلب این کاربر جدید رو محاسبه می کنه و باز هم عددی که به دست میاد با کوئری اول تفاوت داره

*Serializable*

در این حالت علاوه بر قفل شدن ردیفهایی که در شرطها صدق می کنن از INSERT جدید جلوگیری می شه تا اشتباهی پیش نیاد.

برای اینکه Serializable درست کار کنه باید تراکنش ها رو طوری مرتب کنه که  با هم تداخل نداشته باشن و به همین دلیل از وقفه های زمانی استفاده می کنه و  به همین دلیل باعث می شه نرم افزار کمی کند بشه اما پایداری داده ها رو  تظمین می کنه!

*نکته:*

Read committed ایزولاسیون پیش فرض هست و برای تغییر سطح ایزولاسیون باید از این کوئری استفاده کنیم:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

حالا می تونیم با خیال راحت تراکنش کنیم

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
START TRANSACTION
UPDATE `user_mony` SET `mony`=mony-1500000 WHERE (`id`='A')
UPDATE `user_mony` SET `mony`=mony+1500000 WHERE (`id`='B')
COMMIT
*

ROLLBACK*

گاهی کار پیچیده می شه و باید چندین کوئری مختلف رو بزنیم و محسابات مختلفی رو انجام بدیم تا تصمیم بگیریم پولی جابجا بشه یا نه

اگر محاسبات درست بود می تونیم با استفاده از COMMIT تراکنش رو تکمیل کنیم  ولی اگر محاسبات اونی که انتظار داشتیم نبود خیلی ساده می تونیم با استفاده  از ROLLBACK همه کوئری هایی که توی تراکنش استفاده کردیم رو به حالت قبل  برگردونیم

به این صورت
if($has_error=='yes'){
    ROLLBACK
}
else{
    COMMIT
}

----------


## فرزند کوروش

اگه ممکنه يه مثال عملي هم بزن
ممنون

----------

