تابع rollback() در PHP
تابع rollback() یکی از ابزارهای کلیدی مدیریت تراکنش (transaction) در PHP است. هدف آن بازگرداندن (undo) تغییرات انجامشده در دیتابیس تا نقطهٔ شروع تراکنش است. این عمل برای حفظ یکپارچگی دادهها در صورت بروز خطا، قطع ارتباط یا تشخیص شرایط نامناسب بسیار حیاتی است.
چرا rollback مهم است؟
- جلوگیری از دادههای نیمهکامل یا ناسازگار که ممکن است به خطاهای منطقی منجر شوند.
- حفظ خواص ACID (بهخصوص Atomicity و Consistency) در سیستمهای بانک اطلاعاتی.
- مدیریت سادهٔ خطا در برنامههای تحت وب و جلوگیری از پیامدهای ناخواسته عملیات دستهای.
پیشنیازها و نکات کلیدی
- برای استفاده از rollback باید تراکنش آغاز شده باشد (BEGIN، START TRANSACTION یا autocommit=false).
- نوع موتور جدول در MySQL باید تراکنشپذیر باشد (مثلاً InnoDB؛ MyISAM تراکنشپذیر نیست).
- در برخی کتابخانهها مثل PDO باید exception mode فعال شود تا خطاها بهصورت استثنا مدیریت شوند و در بلوک catch اقدام به rollback شود.
مثال عملی با PDO
$pdo = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8', 'user', 'pass');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
try {
$pdo->beginTransaction();
$stmt = $pdo->prepare("UPDATE accounts SET balance = balance - ? WHERE id = ?");
$stmt->execute([100, 1]);
$stmt = $pdo->prepare("UPDATE accounts SET balance = balance + ? WHERE id = ?");
$stmt->execute([100, 2]);
$pdo->commit();
} catch (Exception $e) {
$pdo->rollBack();
error_log('Transaction failed: ' . $e->getMessage());
throw $e; // یا مدیریت مناسب خطا
}در این قطعه کد، ابتدا تراکنش آغاز میشود. در صورت موفقیت دو UPDATE، تغییرات با commit ذخیره میشوند؛ در غیر اینصورت در بلوک catch با rollback همه تغییرات لغو میگردد. فعال کردن PDO::ERRMODE_EXCEPTION تضمین میکند که خطاها به عنوان Exception ظاهر شوند و بتوان بلافاصله rollback را اجرا کرد.
نکات بهینهسازی برای PDO
- همیشه از prepared statements برای جلوگیری از SQL Injection استفاده کنید.
- در صورتی که عملیات طولانی است، بررسی کنید که قفلهای دیتابیس موجب بنبست (deadlock) یا تأخیر نشوند.
- در محیط چندنخی یا کلان، از connection pool و مدیریت صحیح زمان تراکنش بهره ببرید.
مثال با mysqli (روشی پرطرفدار)
$mysqli = new mysqli('localhost', 'user', 'pass', 'testdb');
$mysqli->autocommit(false);
try {
$mysqli->query("UPDATE accounts SET balance = balance - 100 WHERE id = 1");
if ($mysqli->affected_rows === -1) {
throw new Exception('Error updating sender');
}
$mysqli->query("UPDATE accounts SET balance = balance + 100 WHERE id = 2");
if ($mysqli->affected_rows === -1) {
throw new Exception('Error updating receiver');
}
$mysqli->commit();
} catch (Exception $e) {
$mysqli->rollback();
$mysqli->autocommit(true);
error_log('Transaction failed: ' . $e->getMessage());
// مدیریت خطا یا rethrow
}در مثال mysqli، ابتدا autocommit غیرفعال میشود تا بتوان تراکنش را کنترل کرد. در صورت بروز خطا rollback فراخوانی و سپس autocommit فعال میگردد. توجه داشته باشید که mysqli خطاها را به صورت Exception منتشر نمیکند مگر اینکه از mysqli_report یا فعالسازی استثناها استفاده کنید.
Savepoint و شبیهسازی nested transactions
متد rollback() در حالت عادی کل تراکنش را بازمیگرداند. اگر بخواهیم بخش خاصی از تراکنش را لغو کنیم بدون بازگرداندن کل تراکنش، باید از savepoints استفاده کنیم:
$pdo->beginTransaction();
$pdo->exec("SAVEPOINT sp1");
try {
// عملیات اول
$pdo->exec("UPDATE products SET stock = stock - 5 WHERE id = 10");
// اگر نیاز به لغو فقط عملیات اول باشد:
// $pdo->exec("ROLLBACK TO SAVEPOINT sp1");
// در غیر اینصورت ادامه و در نهایت commit کل تراکنش
} catch (Exception $e) {
$pdo->exec("ROLLBACK TO SAVEPOINT sp1"); // یا $pdo->rollBack() برای کل تراکنش
}Savepointها امکان مدیریت پیچیدهتر تراکنشها را میدهند و به نوعی شبیه nested transactions هستند اما توجه کنید که پشتیبانی آن وابسته به DBMS است.
مقایسه کوتاه — PDO vs mysqli
| ویژگی | PDO | mysqli |
|---|---|---|
| استفاده از Exceptions | خروجی قابل تنظیم (PDO::ERRMODE_EXCEPTION) | پیشفرض خطا-کد، امکان تنظیم با mysqli_report |
| پشتیبانی از چند DB | بله (موتورهای مختلف) | صرفاً MySQL |
| Savepoint | با exec قابل استفاده | با query قابل استفاده |
بهترین روشها و نکات امنیتی
- قبل از هر تراکنش مطمئن شوید که جداول از موتور تراکنشپذیر استفاده میکنند (در MySQL: InnoDB).
- تراکنشها را تا حد امکان کوتاه نگه دارید تا قفلها کوتاهمدت باشند و از بنبست جلوگیری شود.
- در عملیات ترکیبی (چندجلسهای و طولانی) حتماً مکانیزم ذخیرهسازی موقت یا قفل منطقی (optimistic/pessimistic locking) را بررسی کنید.
- همیشه در بلوک catch یا در پایان چک وضعیت، rollback را فراخوانی کنید تا از حالت نیمهتعهد جلوگیری شود.
جمعبندی
تابع rollback() یک ابزار ضروری برای بازگرداندن تغییرات در تراکنشهاست و همراه با beginTransaction/commit به شما امکان میدهد که عملیات حساسی را به صورت اتمیک اجرا کنید. آشنایی کامل با رفتار rollback در PDO و mysqli، استفاده از savepointها، و رعایت اصول طراحی تراکنش، موجب برنامهای مقاوم و امن خواهد شد.
آیا این مطلب برای شما مفید بود ؟




