ACID چیست؟ چهار اصل مهم برای حفظ امنیت و صحت اطلاعات در پایگاه داده
تصور کنید در یک فروشگاه اینترنتی، مشتری یک گوشی هوشمند را سفارش میدهد و همزمان هزینه آن را پرداخت میکند. درست در همان لحظه که مبلغ از حساب مشتری کم میشود، ارتباط اینترنتی فروشگاه قطع میشود و اطلاعات سفارش در پایگاه داده ذخیره نمیشود!
حالا چه اتفاقی میافتد؟ پول از حساب مشتری کم شده، اما سفارش او ثبت نشده است. یا حتی ممکن است موجودی محصول تغییر نکند و مشتری دیگری همان گوشی را دوباره خریداری کند.
این دقیقاً یکی از مشکلاتی است که پایگاه دادهها باید از آن جلوگیری کنند.
در نرمافزارهای امروزی، اطلاعاتی مانند پرداختها، سفارشها، موجودی انبار و حساب کاربران باید با دقت بسیار زیادی مدیریت شوند. برای اطمینان از اینکه این اطلاعات هنگام انجام عملیات مختلف دچار تناقض یا خرابی نمیشوند، مفهومی به نام ACID وجود دارد.
اما ACID چیست و چرا برای برنامهنویسان و طراحان پایگاه داده اهمیت دارد؟
ACID چیست؟
ACID مجموعهای از چهار ویژگی مهم در مدیریت تراکنشهای پایگاه داده (Database Transactions) است که کمک میکند عملیاتها به شکل صحیح، قابل اعتماد و بدون ایجاد تناقض انجام شوند.
به زبان ساده، ACID تضمین میکند که اگر قرار است چند عملیات مرتبط با یکدیگر انجام شوند، یا همه آنها بهدرستی انجام شوند یا در صورت بروز مشکل، تغییرات ناقص به حالت قبل برگردند.
کلمه ACID از چهار واژه تشکیل شده است:
- Atomicity (اتمی بودن)
- Consistency (سازگاری)
- Isolation (جداسازی)
- Durability (ماندگاری)
برای درک بهتر این چهار اصل، دوباره به مثال فروشگاه اینترنتی برگردیم.
۱. Atomicity چیست؟ (اتمی بودن)
فرض کنید مشتری یک لپتاپ خریداری میکند. برای ثبت این خرید، چند عملیات باید انجام شوند:
- مبلغ از حساب مشتری کسر شود.
- سفارش در سیستم ثبت شود.
- موجودی لپتاپ در انبار کاهش پیدا کند.
حالا تصور کنید مبلغ از حساب مشتری کم شود، اما قبل از ثبت سفارش، سرور با خطا مواجه شود.
در چنین شرایطی نباید بخشی از عملیات انجام شده باشد و بخش دیگر نیمهکاره باقی بماند.
Atomicity میگوید یک تراکنش باید بهصورت کامل انجام شود یا اصلاً انجام نشود.
یعنی اگر یکی از مراحل تراکنش با شکست مواجه شود، تغییرات انجامشده در آن تراکنش به حالت قبلی برمیگردند. به این عملیات Rollback میگویند.
برای مثال، اگر پرداخت موفق نباشد، سفارش نباید بهعنوان یک خرید قطعی ثبت شود.
یک مثال سادهتر:
فرض کنید میخواهید ۵۰۰ هزار تومان از حساب خود به حساب دوستتان انتقال دهید. این عملیات دو مرحله دارد:
1. کسر ۵۰۰ هزار تومان از حساب شما.
2. اضافه شدن ۵۰۰ هزار تومان به حساب دوستتان.
اگر مرحله اول انجام شود اما مرحله دوم با خطا مواجه شود، چه اتفاقی میافتد؟
Atomicity کمک میکند سیستم از باقی ماندن چنین وضعیت ناقصی جلوگیری کند.
۲. Consistency چیست؟ (سازگاری)
فرض کنید در یک فروشگاه اینترنتی، موجودی یک محصول ۱۰ عدد است. طبق قوانین فروشگاه، موجودی هیچ محصولی نباید کمتر از صفر شود.
حالا اگر چند مشتری همزمان آخرین محصول را سفارش دهند، سیستم باید مراقب باشد که موجودی به عدد منفی نرسد.
اینجاست که اصل Consistency اهمیت پیدا میکند.
Consistency تضمین میکند که هر تراکنش، پایگاه داده را از یک وضعیت معتبر به وضعیت معتبر دیگری منتقل کند.
به عبارت دیگر، اطلاعات باید بعد از انجام هر تراکنش همچنان از قوانین و محدودیتهای تعریفشده در پایگاه داده پیروی کنند.
برای مثال:
- موجودی محصول نباید منفی شود.
- شماره ملی ثبتشده نباید تکراری باشد.
- مبلغ یک سفارش نباید مقدار نامعتبر داشته باشد.
- اطلاعاتی که باید به یکدیگر مرتبط باشند، نباید ارتباط خود را از دست بدهند.
این قوانین معمولاً با کمک محدودیتهایی مانند PRIMARY KEY، FOREIGN KEY، UNIQUE و CHECK در پایگاه داده تعریف میشوند.
بنابراین Consistency کمک میکند اطلاعات حتی پس از انجام تراکنشهای مختلف، همچنان معتبر و قابل اعتماد باقی بمانند.
۳. Isolation چیست؟ (جداسازی)
یکی از اتفاقات رایج در فروشگاههای اینترنتی، خرید همزمان یک محصول توسط چند مشتری است.
تصور کنید تنها یک عدد از یک گوشی موبایل در انبار باقی مانده است.
در همان لحظه، دو مشتری مختلف روی دکمه خرید کلیک میکنند. هر دو درخواست تقریباً همزمان به پایگاه داده ارسال میشوند.
اگر سیستم این درخواستها را بهدرستی مدیریت نکند، ممکن است هر دو مشتری تصور کنند محصول برای آنها ثبت شده است؛ درحالیکه فقط یک عدد موجودی وجود داشته است.
Isolation کمک میکند تراکنشهایی که بهصورت همزمان اجرا میشوند، در دادههای یکدیگر تداخل نامناسب ایجاد نکنند.
یعنی هر تراکنش باید تا حد امکان طوری اجرا شود که انگار بهتنهایی در حال انجام است.
البته این به معنی اجرای اجباری تراکنشها بهصورت کاملاً پشتسرهم نیست؛ بلکه پایگاه داده با استفاده از روشهایی مانند قفلگذاری (Locking) و کنترل نسخههای مختلف اطلاعات (MVCC)، تداخل میان تراکنشها را مدیریت میکند.
برای مثال، SQL Server و PostgreSQL از سازوکارهای مختلفی برای مدیریت تراکنشهای همزمان استفاده میکنند.
آیا تمام تراکنشها باید کاملاً از یکدیگر جدا باشند؟
خیر! پایگاه دادهها میتوانند سطوح مختلفی از جداسازی داشته باشند که به آنها Isolation Level گفته میشود.
این سطوح مشخص میکنند تراکنشها تا چه اندازه میتوانند تغییرات یکدیگر را مشاهده کنند.
چهار سطح رایج عبارتاند از:
- Read Uncommitted
- Read Committed
- Repeatable Read
- Serializable
هرچه سطح جداسازی بیشتر باشد، معمولاً احتمال بروز برخی مشکلات همزمانی کمتر میشود؛ اما ممکن است سرعت و میزان تراکنشهای قابل اجرا نیز تحت تأثیر قرار بگیرد.
۴. Durability چیست؟ (ماندگاری)
تصور کنید مشتری یک خرید اینترنتی انجام داده، مبلغ پرداخت شده و پیام «سفارش شما با موفقیت ثبت شد» را دریافت کرده است.
اما چند ثانیه بعد، برق سرور قطع میشود و سیستم دوباره راهاندازی میشود.
آیا باید سفارش مشتری از بین برود؟
قطعاً نه!
Durability میگوید پس از ثبت موفق یک تراکنش، تغییرات آن باید ماندگار باشند و حتی در صورت بروز مشکلاتی مانند خاموش شدن ناگهانی سیستم، از بین نروند.
پایگاه دادهها برای حفظ اطلاعات از روشهایی مانند ثبت تغییرات در Transaction Log و ذخیرهسازی پایدار استفاده میکنند.
برای مثال، در SQL Server اطلاعات مربوط به تغییرات تراکنش در Transaction Log ثبت میشوند تا سیستم بتواند پس از بروز خطا، وضعیت پایگاه داده را بازیابی کند.
البته ماندگاری به معنی غیرممکن بودن از دست رفتن اطلاعات در تمام شرایط نیست؛ خرابی سختافزار، مشکلات ذخیرهسازی و نبود نسخه پشتیبان همچنان میتوانند خطرناک باشند.
به همین دلیل، تهیه Backup نیز اهمیت زیادی دارد.
یک مثال برنامهنویسی با SQL Server
حالا که با چهار اصل ACID آشنا شدیم، بهتر است ببینیم در عمل چگونه از تراکنشها استفاده میکنیم.
فرض کنید یک سیستم فروشگاهی با SQL Server داریم و میخواهیم خرید یک محصول را ثبت کنیم.
در این مثال، ابتدا موجودی محصول کاهش پیدا میکند و سپس سفارش در جدول مربوطه ثبت میشود.
BEGIN TRANSACTION;
UPDATE Products
SET Stock = Stock - 1
WHERE Id = 10 AND Stock > 0;
INSERT INTO Orders (ProductId, Quantity)
VALUES (10, 1);
COMMIT TRANSACTION;
در این کد:
- BEGIN TRANSACTION شروع یک تراکنش جدید است.
- UPDATE موجودی محصول را یک واحد کاهش میدهد.
- INSERT سفارش جدید را ثبت میکند.
- COMMIT تغییرات تراکنش را نهایی میکند.
اما یک نکته مهم وجود دارد!
برای اینکه مثال واقعاً ایمن باشد، باید بررسی کنیم که موجودی محصول کافی بوده و دستور کاهش موجودی موفق شده است. همچنین اگر هر مرحله با خطا مواجه شد، باید تراکنش را با ROLLBACK برگردانیم.
در یک پیادهسازی کاملتر میتوانیم از این ساختار استفاده کنیم:
BEGIN TRY
BEGIN TRANSACTION;
UPDATE Products
SET Stock = Stock - 1
WHERE Id = 10 AND Stock > 0;
IF @@ROWCOUNT = 0
THROW 50001, 'Product is unavailable', 1;
INSERT INTO Orders (ProductId, Quantity)
VALUES (10, 1);
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
IF XACT_STATE() <> 0
ROLLBACK TRANSACTION;
THROW;
END CATCH;
در این نسخه، اگر محصول موجود نباشد یا یکی از دستورات با خطا مواجه شود، تراکنش بهدرستی Rollback میشود.
البته این مثال برای درک مفهوم ACID است و در یک سیستم پرداخت واقعی، مدیریت وضعیت پرداخت، ارتباط با درگاه بانکی و هماهنگی میان سرویسهای مختلف نیز باید بهصورت جداگانه طراحی شوند.
تفاوت چهار اصل ACID در یک نگاه
اگر بخواهیم این چهار ویژگی را خیلی ساده از یکدیگر جدا کنیم:
- Atomicity: یا همه مراحل انجام میشوند یا هیچکدام.
- Consistency: اطلاعات همیشه باید از قوانین و محدودیتهای پایگاه داده پیروی کنند.
- Isolation: تراکنشهای همزمان نباید باعث ایجاد تداخل نامعتبر شوند.
- Durability: تغییرات ثبتشده پس از موفقیت تراکنش باید ماندگار باشند.
این چهار اصل در کنار یکدیگر باعث میشوند پایگاه داده بتواند اطلاعات را با اطمینان بیشتری مدیریت کند.
آیا همه پایگاه دادهها از ACID پشتیبانی میکنند؟
بسیاری از پایگاه دادههای رابطهای مانند SQL Server، PostgreSQL، MySQL و Oracle از تراکنشهای ACID پشتیبانی میکنند.
اما این موضوع به معنی آن نیست که تمام پایگاه دادهها دقیقاً یکسان عمل میکنند.
برای مثال، در MySQL پشتیبانی از تراکنشها به نوع موتور ذخیرهسازی بستگی دارد و موتور InnoDB از تراکنشهای ACID پشتیبانی میکند.
از طرف دیگر، برخی پایگاه دادههای NoSQL نیز قابلیتهای تراکنشی دارند، اما نحوه پیادهسازی و محدوده تضمینهای آنها ممکن است متفاوت باشد.
بنابراین هنگام انتخاب پایگاه داده برای یک پروژه، باید به نوع اطلاعات، میزان همزمانی کاربران و میزان حساسیت عملیاتها توجه کرد.
ACID در چه پروژههایی اهمیت بیشتری دارد؟
تقریباً هر نرمافزاری که با ذخیره و تغییر اطلاعات سروکار دارد، میتواند از اصول ACID بهره ببرد؛ اما در بعضی پروژهها اهمیت آن بسیار بیشتر است:
- سیستمهای بانکی: برای انتقال وجه، برداشت و واریز پول.
- فروشگاههای اینترنتی: برای ثبت سفارش، پرداخت و مدیریت موجودی.
- سامانههای رزرو: برای جلوگیری از رزرو همزمان یک بلیت یا اتاق توسط چند نفر.
- سیستمهای حسابداری: برای ثبت دقیق تراکنشهای مالی.
- سامانههای مدیریت کاربران: برای حفظ ارتباط صحیح میان اطلاعات کاربران و حسابهای آنها.
در چنین پروژههایی، یک خطای کوچک در مدیریت اطلاعات میتواند باعث ضرر مالی، نارضایتی کاربران یا ایجاد دادههای اشتباه شود.
جمعبندی
ACID یکی از مهمترین مفاهیم در دنیای پایگاه داده است که از چهار اصل Atomicity، Consistency، Isolation و Durability تشکیل میشود.
این چهار ویژگی کمک میکنند تراکنشها بهدرستی اجرا شوند، اطلاعات معتبر باقی بمانند، عملیاتهای همزمان با یکدیگر تداخل نامناسب نداشته باشند و تغییرات ثبتشده از بین نروند.
اگر قصد دارید وارد دنیای برنامهنویسی بکاند، طراحی پایگاه داده یا توسعه نرمافزارهای سازمانی شوید، آشنایی با ACID و نحوه استفاده از Transaction در SQL Server یکی از مهارتهای مهمی است که باید یاد بگیرید.
فراموش نکنید که یک نرمافزار حرفهای فقط نرمافزاری نیست که امکانات زیادی داشته باشد؛ بلکه باید بتواند اطلاعات کاربران را نیز به شکل صحیح و قابل اعتماد مدیریت کند.
فرایانه؛ جایی که مفاهیم پیچیده برنامهنویسی را به زبان ساده، کاربردی و قابل فهم آموزش میدهیم. 💚