في هذه الصفحة
المقدمة
في البداية تعالى نتخيل مثال من الواقع اللي بنعيشه كل يوم عشان نبدا نفهم عنوان المقال بتاعنا.
تخيل صديقي العزيز انك في مطعم زحمة جدا وكل الناس اللي قاعدين على طاولات الطعام بيتنافسوا مين يلفت انتباه الراجل اللي بيجي ياخد الطلبات عشان ياخد باله ويجيلهم ويجيب لهم الاوردر بتاعهم طبعا هتلاقي كل الناس عاوزين يوصلو للراجل ده في نفس الوقت!
نفس الكلام ياصديقي بيحصل في عالم قواعد البيانات و انظمة الكمبيوتر لما يتنافس عدة مستخدمين او عمليات للوصول لنفس البيانات في نفس الوقت.
ايه هو الـ Locking
هنا بقى بيكون دور ال locking كأنه حارس بيتحكم في تدفق العملاء المتحمسين يعني بيتحكم في ال flow اعتبره شرطى المرور اللي بيضمن ان ميحصلش فوضي لو في عدة مستخدمين هيعملو access او قرأو و هيعدول نفس قطعة البيانات بشكل concurrently.
يبقى دور ال locking هنا هو الحفاظ على سلامة وامن البيانات ومنع التعارض اللي ممكن يحصل على البيانات لو في concurrent operations هتحصل عليها او concurrent users عاوزين ي access هذه البيانات.
يعني هنحمي الراجل بتاع المطعم وننظم عملية الوصول ل ايه لعمل الطلبات قبل مالناس تزهق وتقوم تضربه 😅
أنواع الـ Locking
استراتيجية ال locking دي بقى بتتقسم لنوعين وكل نوع منهم ليه اسلوبه في الحفاظ على امن وسلامة البيانات ومنع تعارض ال data النوع الأول اسمه Pessimistic Locking والنوع التاني اسمه Optimistic Locking.
الـ Pessimistic Locking
والنوع ده بيفترض الاسوء انه هيحصل فبيأمن نفسه بدري بدري وبنقول عليها concurrency control mechanism الية للتحكم في ال concurrency التزامن وبيتفرض انه هيحصل تعارض للداتا وهتكون غير متسقة يعني inconsistent لما عدد من المستخمدين او العمليات ت access الداتا في نفس الوقت .
النوع ده فكرته انه يعمل lock او يعمل قفل على الداتا وبيمنع وصول اي مستخدم تاني او عملية تانيه للداتا طالما في مستخدم او عملية شغاله دلوقتي على الداتا دي لحد ما العملية تخلص يقوم يفتح القفل فيجي مستخدم تاني و عملية تانيه ت access الداتا دي فيقفل القفل تاني ومدش يعرف يوصلها لحد ما العمليه اللي بتم تخلص يقوم يفتح القفل تاني وهكذا.
يعني بيحط قفل بشكل استباقي وده اللي بنقول عليه Acquiring Locks Upfront بتحط القفل مقدما.
خصائص الـ Pessimistic Locking
- الـ Acquiring Locks Upfront: زي ماقولنا بيحط القفل مسبقا قبل مايحصل اي عملية read او write على الدتا عشان يمنع العمليات المتزامنه التانيه من الوصل للبيانات بشكل متزامن concurrently.
- الـ Exclusive Access: يعني القفل هيسمح بس بالوصول الحصري للداتا يعني واحد بس اللي هيوصل والباقي هيستنو لحد مايخلص ويفتح القفل تاني ويدخل واحد بعده هيخش برده بشكل حصري وهكذا.
- الـ Potential for Waiting: طبعا لما هيحص lock على الدتا لحد ما العملية اللي شغاله تخلص ده معناته ان برده باقي العمليات اللي مستنيه برده هتكون عندها waiting time لانها منتظرة العملية تخلص .
- الـ Different Granularities: ال Pessimistic locking ممكن تعمله على مستوى table او على row او على مستوي database يعني بيشتغل على تفاصيل مختلفة.
Pessimistic Locking in DotNet and EF Core
تعالى نشوف مثال في ال .net في Entity Framework Core، مفيش دعم مباشر للتأمين المتشائم (Pessimistic Locking) كجزء من الإطار framework نفسه. لكن ممكن تنفيذ ال Pessimistic Locking باستخدام بعض الاستراتيجيات اليدوية.
- استخدام Transactions: تقدر تستخدم الـ Transactions مع ال lock على مستوى قاعدة البيانات. مثلاً، ممكن تستخدم
Begin Transaction
وتعمل قفل على مستوى ال records . - تنفيذ الاستعلامات المباشرة: باستخدام
ExecuteSqlRaw
أوExecuteSqlInterpolated
، تقدر تنفذ استعلام SQL يقفل ال record .
using (var context = new YourDbContext())
{
using (var transaction = context.Database.BeginTransaction())
{
var record = context.Records.FromSqlRaw("SELECT * FROM Records WITH (UPDLOCK, ROWLOCK) WHERE Id = {0}", id).FirstOrDefault();
// تنفيذ التعديلات
record.Property = newValue;
context.SaveChanges();
transaction.Commit();
}
}
خلى بالك ان:
- الـ Pessimistic Locking قد يؤثر على الأداء، خصوصًا في الأنظمة اللي فيها ضغط عالي من المستخدمين.
- تأكد من مراجعة تصميم قاعدة البيانات والتعامل مع العمليات بشكل مناسب لتفادي ال Deadlocks.
- كمان ممكن يحصل exceptions لو في conflicts بسبب ال lock اللي على ال records فلازم تاخد بالك وتتعامل مع ال exceptions دي لطريقة مناسبة .
تقدروا دلوقتي تشتركوا في النشرة الأسبوعية لاقرأ-تِك بشكل مجاني تمامًا عشان يجيلكوا كل جديد بشكل أسبوعي فيما يخص مواضيع متنوعة وبشروحات بسيطة وسهلة وبجودة عالية 🚀
النشرة هيكون ليها شكل جديد ومختلف عن شكلها القديم وهنحاول انها تكون مميزة ومختلفة وخليط بين المحتوى الأساسي اللي بينزل ومفاجآت تانية كتير 🎉
بفضل الله قمنا بإطلاق قناة اقرأ-تِك على التليجرام مجانًا للجميع 🚀
آملين بده اننا نفتح باب تاني لتحقيق رؤيتنا نحو إثراء المحتوى التقني باللغة العربية ، ومساعدة لكل متابعينا في انهم يوصلوا لجميع أخبار اقرأ-تِك من حيث المقالات ومحتوى ورقة وقلم والنشرة الأسبوعية وكل جديد بطريقة سريعة وسهلة
مستنينكوا تنورونا , وده رابط القناة 👇
الـ Optimistic Locking
وهي بتعتمد على افتراض أن الصراعات اللي هتحصل بين المستخدمين للوصل لنفس الدتا نادرة. في النوع ده من ال locking، مش بنقفل السجلات ال records لما بن read الداتا ، بس بنتحقق من صحة البيانات عند حفظ التغييرات. ازاي الكلام ده ؟ وبنتحقق من ايه وليه ؟
عندنا 3 خطوات عشان نفهم إزاي بيشتغل Optimistic Locking.
ازاي الـ Optimistic Locking بيشتغل
- قراءة البيانات: المستخدم يقرأ البيانات من قاعدة البيانات بدون .lock
- تعديل البيانات: المستخدم يقوم بتعديل البيانات locally.
- التحقق عند الحفظ: عند محاولة حفظ البيانات، يتم التحقق إذا كانت البيانات قد تغيرت من قبل مستخدم آخر منذ أن تم تحميلها. إذا كانت البيانات قد تم تعديلها، فإن العملية تفشل، ويجب على المستخدم تحديث بياناته.
وهنفهم اكثر لما نشوف مثال.
Optimistic Locking in DotNet and EF Core
مثلا في ال EFCore لما ناجي ننفذ ال Optimistic Locking بيكون في خاصية تُسمى "توقيت الإصدار" (Concurrency Token) والخاصية دي بستخدمها مع ال entity وبتمثل توقيت الاصدار بتمثل الاصدار بتاع كل record .
ازاي بقى بتستغل خاصية الاصدار دي : (Concurrency Token):
- بنعرف خاصية الاصدار من خلال اننا بنضيف لل entity وبتكون من نوع byte [ ] او timestamp والخاصية دي بتسجل النسخة الحالية من ال record ده في قاعدة البيانات وكل مره بيتم تعديل السجل يعني بتحدث السجل ده.
public class Record
{
public int Id { get; set; }
public string Property { get; set; }
[Timestamp] // خاصية الإصدار
public byte[] RowVersion { get; set; }
}
- التحقق عند الحفظ: لما المستخدم يحاول يحفظ التغييرات، EF Core هيتحقق تلقائيًا إذا كانت النسخة (RowVersion) اللي في قاعدة البيانات هي نفس النسخة اللي كان المستخدم عاملها read.
لو النسختين مختلفتين يبقى في حد عدل على الداتا دي والتعديل بتاعه اتحفظ بس انت كنت عامل read من الدتا القديمة اللي هي قبل ماالتعديل بتاع الراجل ده يتحفظ فانت دلوقتي مش معاك اخر تعديل فعملية التعديل بتاعك هتفشل لانك مش معاك اخر تحديث من الدتا فلازم تروح تجيب اخر تحديث وبعدين تعمل التعديل بتاعك وبرده وانت بتحفظ البيات بعد التعديل هيروح EF Core يتحقق من ال ROWVersion لو طلعت مطابقه للنسخة اللي معاك هينفذ تعديل لو كانت غير مطابقه يبقى زي ماقلنا حد تاني نفذ تعديل على الداتا وتعديله اتنفذ قبلك فيجب عليك انك تاخد اخر تحديث وهكذا
using (var context = new YourDbContext())
{
var record = context.Records.Find(id);
// تنفيذ التعديلات
record.Property = newValue;
try
{
context.SaveChanges();
}
catch(DbUpdateConcurrencyException)
{
// تم اكتشاف تعارض في البيانات
// هنا ممكن نعيد تحميل البيانات أو تعرض رسالة للمستخدم
}
}
باستخدام توقيت الإصدار، أنت بتضمن إن البيانات هتفضل سليمة ومافيش تعارضات بتحصل. وفي حالة حدوث تعارض، بتقدر تعالج الموقف بسهولة. وبالتالي، Optimistic Locking يعتبر طريقة فعالة في بيئات العمل المتعددة.
في الختام
- الـ Pessimistic locking يوفر أمانًا أكبر ولكن قد يؤثر على الأداء.
- الـ Optimistic Locking يوفر أداءً أفضل ولكن يتطلب إدارة جيدة لحالات التعارض.
إذا كان لديك تطبيق يواجه سيناريوهات مختلطة، قد تحتاج إلى استخدام كلا الطريقتين في أماكن مختلفة وفقًا لمتطلبات كل جزء من التطبيق.