پادشاهِ کُدنویسا شو!
کینگتو - آموزش برنامه نویسی تخصصصی - دات نت - سی شارپ - بانک اطلاعاتی و امنیت

Concurrency Token چیست؟

10 بازدید 0 نظر ۱۴۰۴/۱۲/۱۵
در دنیای سیستم‌های چندکاربره، یکی از بزرگترین چالش‌ها مدیریت «تغییرات همزمان» است. تصور کنید دو نفر همزمان سعی می‌کنند موجودی یک کیف پول دیجیتال را تغییر دهند؛ اگر سیستم هوشمندانه عمل نکند، یکی از این تراکنش‌ها باعث از بین رفتن دیگری می‌شود. اینجاست که مفهومی به نام Concurrency Token (توکن همزمانی) به عنوان فرشته نجات داده‌های شما وارد عمل می‌شود.

در این مقاله، به بررسی دقیق مفهوم Concurrency Token، نحوه عملکرد آن در لایه‌های دسترسی به داده (مخصوصاً Entity Framework Core) و پیاده‌سازی آن با مثال‌های کاربردی می‌پردازیم.

 

مشکل اصلی: بروزرسانی گمشده (Lost Update)

قبل از اینکه بگوییم توکن همزمانی چیست، باید بدانیم چه مشکلی را حل می‌کند. در پایگاه داده، وقتی دو کاربر همزمان یک رکورد را می‌خوانند و هر دو سعی می‌کنند آن را تغییر دهند، سناریوی زیر رخ می‌دهد:

  1. کاربر الف موجودی حساب را می‌بیند: ۱۰۰ هزار تومان.

  2. کاربر ب موجودی همان حساب را می‌بیند: ۱۰۰ هزار تومان.

  3. کاربر الف ۲۰ هزار تومان واریز می‌کند و موجودی را به ۱۲۰ هزار تومان تغییر داده و ذخیره می‌کند.

  4. کاربر ب ۱۰ هزار تومان برداشت می‌کند و بر اساس همان ۱۰۰ تومانی که دیده بود، موجودی را به ۹۰ هزار تومان تغییر داده و ذخیره می‌کند.

نتیجه فاجعه‌بار: واریز ۲۰ هزار تومانی کاربر الف کاملاً نادیده گرفته می‌شود و موجودی نهایی به جای ۱۱۰ هزار تومان، روی ۹۰ هزار تومان می‌ماند. به این اتفاق Lost Update می‌گوییم.

 

راه‌حل: کنترل همزمانی خوش‌بینانه (Optimistic Concurrency)

دو راه کلی برای جلوگیری از این مشکل وجود دارد:

  • Pessimistic Locking (بدبینانه): به محض اینکه کاربر الف رکورد را خواند، دیتابیس آن را قفل می‌کند تا هیچکس دیگر حتی نتواند آن را بخواند. این کار سرعت سیستم را به شدت کاهش می‌دهد.

  • Optimistic Concurrency (خوش‌بینانه): ما به هیچ‌کس قفل نمی‌دهیم، اما هنگام ذخیره کردن چک می‌کنیم که آیا داده‌ها از زمانی که کاربر آن‌ها را خوانده، تغییر کرده‌اند یا خیر.

Concurrency Token ابزاری است که برای پیاده‌سازی روش خوش‌بینانه استفاده می‌شود.

 

Concurrency Token چیست؟

Concurrency Token یک ویژگی (Property) در مدل داده‌ای شماست که نقش "برچسب وضعیت" را بازی می‌کند. وقتی می‌خواهید رکوردی را آپدیت کنید، پایگاه داده چک می‌کند که آیا مقدار این توکن هنوز همان مقداری است که در زمان "خواندن" بود یا خیر.

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

 

نحوه عملکرد فنی در SQL

وقتی شما یک فیلد را به عنوان Concurrency Token معرفی می‌کنید، در پشت صحنه، دستور UPDATE در SQL تغییر می‌کند.

  • بدون توکن:

    UPDATE Accounts SET Balance = 90000 WHERE Id = 1

  • با توکن:

    UPDATE Accounts SET Balance = 90000 WHERE Id = 1 AND VersionToken = 'ABC'

اگر کاربر دیگری در این فاصله VersionToken را به 'XYZ' تغییر داده باشد، شرط WHERE برقرار نمی‌شود، هیچ ردیفی آپدیت نمی‌گردد و برنامه متوجه تداخل می‌شود.

 

پیاده‌سازی در Entity Framework Core (مثال عملی)

در EF Core، شما به دو روش می‌توانید یک ویژگی را به عنوان توکن همزمانی معرفی کنید:

روش اول: استفاده از ویژگی‌های موجود

فرض کنید می‌خواهیم فیلد Email در کلاس کاربر، توکن ما باشد:

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    
    [ConcurrencyCheck] // این فیلد تبدیل به توکن همزمانی می‌شود
    public string Email { get; set; }
}

روش دوم: استفاده از RowVersion (بهترین روش)

در SQL Server، نوع داده‌ای به نام rowversion وجود دارد که با هر بار تغییر رکورد، به صورت خودکار توسط خود دیتابیس تغییر می‌کند. این بهترین گزینه برای Concurrency Token است.

public class Product
{
    public int Id { get; set; }
    public string Title { get; set; }
    public decimal Price { get; set; }

    [Timestamp] // در دیتابیس به rowversion تبدیل می‌شود
    public byte[] RowVersion { get; set; }
}

 

سناریوی کامل: مدیریت خطا در زمان تداخل

حالا ببینیم در کد برنامه چطور با این تداخل برخورد می‌کنیم. وقتی دو کاربر همزمان تلاش کنند، EF Core خطای DbUpdateConcurrencyException را پرتاب می‌کند.

try 
{
    var product = context.Products.First(p => p.Id == 1);
    product.Price = 500;
    
    context.SaveChanges();
}
catch (DbUpdateConcurrencyException ex)
{
    // اوه! یک تداخل رخ داده است.
    foreach (var entry in ex.Entries)
    {
        if (entry.Entity is Product)
        {
            var proposedValues = entry.CurrentValues; // مقداری که ما می‌خواستیم ذخیره کنیم
            var databaseValues = entry.GetDatabaseValues(); // مقداری که الان در دیتابیس است

            if (databaseValues == null)
            {
                Console.WriteLine("این کالا توسط شخص دیگری حذف شده است.");
            }
            else
            {
                Console.WriteLine("این کالا توسط شخص دیگری ویرایش شده. دوباره تلاش کنید.");
                // در اینجا می‌توانید تصمیم بگیرید: 
                // ۱. مقدار جدید دیتابیس را به کاربر نشان دهید
                // ۲. یا تغییرات خودتان را به زور اعمال کنید (Client Wins)
            }
        }
    }
}

 

چه زمانی از Concurrency Token استفاده کنیم؟

استفاده از این توکن‌ها هزینه پردازشی کمی دارد، بنابراین وسوسه‌انگیز است که برای همه جداول استفاده شود. اما بهتر است اولویت‌بندی کنید:

  • حیاتی: جداول مالی، موجودی انبار، سیستم‌های رزرو بلیط.

  • متوسط: پروفایل کاربری، تنظیمات اپلیکیشن.

  • غیرضروری: جداول لاگ (Log)، کامنت‌های زیر پست (معمولاً تداخل در کامنت‌ها بحران ایجاد نمی‌کند).

 

مقایسه روش‌های مختلف

روش مزایا معایب
RowVersion (Timestamp) خودکار توسط دیتابیس مدیریت می‌شود و بسیار دقیق است. وابسته به دیتابیس (SQL Server) است.
ConcurrencyCheck روی هر فیلد دلخواهی قابل اجراست. اگر فیلد تغییر نکند، تداخل تشخیص داده نمی‌شود.
Shadow Properties کد کلاس مدل را شلوغ نمی‌کند. پیاده‌سازی آن در Fluent API کمی پیچیده‌تر است.

 

نتیجه‌گیری

Concurrency Token یک مکانیزم دفاعی برای حفظ یکپارچگی داده‌ها در محیط‌های چندکاربره است. با استفاده از روش Optimistic Concurrency، شما به کاربران اجازه می‌دهید بدون معطلی و قفل شدن دیتابیس کار کنند، و تنها در لحظه نهایی از "بروزرسانی‌های گمشده" جلوگیری می‌کنید. در اکثر پروژه‌های دات‌نتی، استفاده از ویژگی [Timestamp] به همراه مدیریت خطای DbUpdateConcurrencyException استانداردترین راه حل ممکن است.

 
 
لینک استاندارد شده: rlh9n

0 نظر

    هنوز نظری برای این مقاله ثبت نشده است.
جستجوی مقاله و آموزش
دوره‌ها با تخفیفات ویژه