谨防截断表
注意在任何 RDBMS 中截断表,尤其是当您想使用显式事务来实现提交/回滚功能时。请阅读此答案的“我的建议”。
DDL 语句执行隐式提交
截断表语句是数据定义语言 (DDL) 语句,因此截断表语句在执行时会向数据库触发隐式 COMMIT。如果您执行TABLE TRUNCATE,那么数据库将被隐式提交——即使TABLE TRUNCATE 在START TRANSACTION 语句中——您的表将被截断并且ROLLBACK 将不会恢复它。
因为 truncate table 语句执行隐式提交,Maxence 的答案没有按预期执行(但这并没有错,因为问题是“如何截断表”)。他的回答没有按预期执行,因为它截断了try 块中的表,并假设如果出现问题,可以在catch 块中恢复表。这是一个错误的假设。
其他用户在此线程中的 cmets 和经验
ChrisAelbrecht 无法让 Maxence 的解决方案正常工作,因为您无法回滚 truncate table 语句,即使 truncate table 语句位于显式事务中。
不幸的是,user2130519 因提供正确答案而被否决(-1 直到我投赞成票)——尽管他这样做并没有证明他的答案是正确的,这就像在没有展示你的工作的情况下做数学一样。
我的推荐DELETE FROM
我的建议是使用DELETE FROM。在大多数情况下,它将按照开发人员的预期执行。但是,DELETE FROM 也并非没有缺点——您必须明确地重置表的自动增量值。要重置表的自动增量值,您必须使用另一个 DDL 语句--ALTER TABLE--并且同样,不要在 try 块中使用 ALTER TABLE。它不会按预期工作。
如果您想知道什么时候应该使用DELETE FROM 和TRUNCATE,请参阅Pros & Cons of TRUNCATE vs DELETE FROM。
如果你真的需要,这里是截断的方法
现在,说了这么多。如果您真的想使用 Doctrine2 截断表格,请使用:(以下是 Maxence 正确截断表格的答案部分)
$cmd = $em->getClassMetadata($className);
$connection = $em->getConnection();
$dbPlatform = $connection->getDatabasePlatform();
$connection->query('SET FOREIGN_KEY_CHECKS=0');
$q = $dbPlatform->getTruncateTableSql($cmd->getTableName());
$connection->executeUpdate($q);
$connection->query('SET FOREIGN_KEY_CHECKS=1');
如何删除具有回滚/提交功能的表。
但是,如果您想要回滚/提交功能,则必须使用DELETE FROM:(以下是 Maxence 答案的修改版本。)
$cmd = $em->getClassMetadata($className);
$connection = $em->getConnection();
$connection->beginTransaction();
try {
$connection->query('SET FOREIGN_KEY_CHECKS=0');
$connection->query('DELETE FROM '.$cmd->getTableName());
// Beware of ALTER TABLE here--it's another DDL statement and will cause
// an implicit commit.
$connection->query('SET FOREIGN_KEY_CHECKS=1');
$connection->commit();
} catch (\Exception $e) {
$connection->rollback();
}
如果需要重新设置自增值,记得拨打ALTER TABLE <tableName> AUTO_INCREMENT = 1。