TRUNCATE, затем ROLLBACK, но строки всё равно исчезли — объясните почему
Разработчик выполнил это внутри явной транзакции и ждал, что ROLLBACK восстановит таблицу, но строки не вернулись:
BEGIN;
TRUNCATE TABLE orders;
ROLLBACK;
SELECT COUNT(*) FROM orders; -- вернул 0, а не исходное число
Определите, почему ROLLBACK не восстановил строки.
В MySQL и многих СУБД TRUNCATE — это DDL, а DDL вызывает неявный COMMIT открытой транзакции перед запуском. Поэтому TRUNCATE уже зафиксирован, и ROLLBACK нечего отменять. DELETE — это DML, и он бы откатился.
- ✗Считать, что TRUNCATE участвует в окружающей транзакции, как DELETE
- ✗Винить тайминг или сброс на диск, а не неявный commit
- ✗Думать, что ROLLBACK вообще не отменяет удаление строк, даже DELETE
- →Какие ещё команды вызывают тот же неявный commit перед выполнением?
- →Как переписать операцию, чтобы она была действительно откатываемой?
TRUNCATE is DDL, and on MySQL (and most engines) any DDL statement forces an implicit COMMIT of the open transaction before it executes. So BEGIN; TRUNCATE ... actually commits everything up to that point and empties the table outside the transaction's control; the following ROLLBACK has no open work to reverse.
To make the operation reversible, use DML instead:
BEGIN;
DELETE FROM orders; -- DML: participates in the transaction
ROLLBACK; -- restores every row
DELETE is logged row-by-row and is fully transactional, so ROLLBACK brings the rows back. The trade-off is speed: TRUNCATE is far faster on a large table precisely because it skips per-row logging — which is also why it cannot be rolled back.