تکنیکی هست که برای کارهای همزمان (concurrent) ایجاد شده و به کابران یا thread ها اجازه نمیده که کارهای همدیگه رو بازنویسی یا تغییر بدهند. به عبارت دیگر حفاظت از داده خود برای جلوگیری از تغییر در همان لحظه.
اگر اپلیکشن شما یک کاربر همزمان برای اپدیت داده در لحظه خواهد داشت خب جای نگرانی نیست. مشکل زمانی ایجاد میشود که کاربران مختلف در یک لحظه قصد دسترسی و تغییر داده مشابه را در لحظه دارند. اینجاست به عنوان یک توسعه دهنده مهمه که درباره همزمانی (concurrency) فکر کنی.
فرض کنید کاربرای زیادی قصد خرید کالایی از فروشگاه اینترنتی عی رو دارند که موجودی اون 1 هست. و فروشگاه اینترنتی موردنظر توی تلویزیون, سایت های مختلف تبلیغ کرده است. و 2000 هزار نفر کاربر قصد خرید این ایتم رو دارند و شما فقط میتونید این ایتم رو به یک نفر بفروشید.
برای مدیریت این وضعیت از قفل های دیتابیسی استفاده میکنید اگر چنین اتفاقی نیوفته امکانه داره یک ایتم که فقط یک موجودی داره به 1999 نفر دیگه فروخته بشه.
مثال های فراوانی از این مشکلات همزمانی میشه زد.....
تو این مقاله قصد داریم با دو تا از روش های database locking اشنا بشیم. optimistic and pessimistic locking.
هر کدوم از این روش های لاک کردن دیتابیس مزایا و معایب خودشون رو دارند و یک اپلیکشن خوب از ترکیبی از این دو روش استفاده میکنه.
تعریف استراتژی عی هست که کار اون تشخیص و حل در زمان وقوع collisions (تصادف, برخورد) در اپلیکشن شماست و پیشنهاد میشه در وضعیت های چند کاربره که برخورد و مشکل بسیار نادر هست استفاده بشود. در این روش رکورد دیتابیس عملا قفل نمیشه! و با یک فیلد خاصی در دیتابیس کنترل میشه مثل (version, timestamp, etc).
روش Optimistic Locking یک استراتژی متداول هست. چون اکثر اپلیکشن ها طراحی شون جوری بوده که کاربر مشخص فقط قصد اپدیت کردن دیتایی رو داره که متعلق به خودش هست و خیلی دوره که دو کاربر قصد اپدیت کردن یک رکورد اون هم به صورت همزمان رو داشته باشن.
باز هم میگم ایده پشت Optimistic Locking این هست که collisions در اپلیکشن ما به ندرت اتفاق میوفته. تمام!
خب من یه مثال ساده میزنم از این روش توی فریمورک RubyOnRails
لازم میدونم بگم این روش های لاک کردن کانسپت هست. دلیل نمیشه که من از روبی مثال میزنم این روش توی php, java و ... نباشه - تمام فریمورک ها این ویژگی ها رو پشتیبانی میکنن به روشی و صرفا باید بگردید دنبالش.
برای این که بتونیم از این روش استفاده کنیم باید یک فیلد به اسم lock_version به جدولمون اضافه کنیم.
خب حالا با استفاده تست spec این روش رو تست میکنیم:
خب توی کد بالا من قبل از اینکه ابجکت t1 ذخیره بشه اون رو تغییر دادم. اتفاقی که حالا اینجا میوفته زمانی که آبجت دوم من یعنب t2 میخواد ذخیره بشه یک Exception پرتاب میشه. :) به همین خوشمزگی.
خب optimistic locking یکسری مزایا داره. از این جهت که ویژگی خاصی سمت دیتابیس نمیخواد. پیاده سازیش کار آسونی هست. وشما به راحتی میتونید اررور هندلینگ رو انجام بدید.
اصلی ترین عیب یا مشکل optimistic locking عمل اپدیت یک ذره کندتر میشه چون فیلد lock version قبل ش باید چک بشه.
روش Pessimistic Locking عمل لاک کردن رکورد رو سمت دیتابیس انجام میده و این روش توی اکثر دیتابیس ها پیشبینی و پیاده سازی شده. اطلاعات بیشتر در رابطه با لاک کردن دیتایس رو میتونید توی لینک های زیر پیدا کنید.
MySQL: https://dev.mysql.com/doc/refman/5.7/en/innodb-locking-reads.html
PostgreSQL: https://www.postgresql.org/docs/current/interactive/sql-select.html#SQL-FOR-UPDATE-SHARE
خب همینطور که میدونید این روش هم در فریمورک های مختلف توسط ORM مورد استفاده پیاده سازی شده. باز هم شما رو به مثالی عملی از استفاده از این روش توی فریمورک روبی ان ریلز دعوت میکنم.
توی تکه کد بالا از متدی به اسم lock استفاده شده. این متد رکورد مورد نظر رو در سطح دیتابیس لاک میکند و ریکوئست هایی که قصد دسترسی به این رکورد را دارند بلاک میشوند.
استفاده از روش Optimistic Locking برای اپلیکشن هایی که در حال حاضر فعالیت میکنند به نظر انتخاب بهتری است. دلایلی هم وجود دارد.
برای هندل کردن اررور Pessimistic Locking باید روشی اتخاص کنید! پیاده سازی روش Pessimistic Locking کار اسونی هست ولی باید در نظر داشته باشید که امکان دارد یک پردازشی در اپلیکشن شما منتظر آزاد شدن قفل دیتابیس باشد. امکان به وجود امدن deadlock در اپلیکشن شما وجود دارد!
استفاده از هر یک از این روش ها بستگی به معماری و نیاز اپلیکشن شما دارد.
تمام.