如何使用原则 2 截断表格?当心截断表

2022-08-30 12:45:44

我假设我需要构建一个本机查询来使用Doctine2截断表。

$emptyRsm = new \Doctrine\ORM\Query\ResultSetMapping();
$sql = 'TRUNCATE TABLE Article';
$query = em()->createNativeQuery($sql, $emptyRsm);
$query->execute();

这给出了错误

SQLSTATE[HY000]: General error

我需要对代码进行哪些更改才能实现此目的?


答案 1

当心截断表

请注意在任何 RDBMS 中截断表,尤其是在要将显式事务用于提交/回滚功能时。请阅读此答案的“我的建议”。


DDL 语句执行隐式提交

截断表语句是数据定义语言 (DDL) 语句,因此截断表语句在执行时会触发对数据库的隐式 COMMIT。如果执行 a,则数据库将隐式提交到 (即使 位于语句中),您的表将被截断,并且 a 将不会还原它。TABLE TRUNCATETABLE TRUNCATESTART TRANSACTIONROLLBACK

由于截断表语句执行隐式提交,因此 Maxence 的答案不会按预期执行(但这并不错误,因为问题是“如何截断表”)。他的答案没有按预期执行,因为它截断了块中的表,并假设如果出现问题,可以在块中恢复表。这是一个不正确的假设。trycatch


其他用户在此线程中的评论和体验

ChrisAelbrecht 无法使 Maxence 的解决方案正常工作,因为您无法回滚截断表语句,即使截断表语句位于显式事务中也是如此。

不幸的是,user2130519因为提供正确的答案而被否决(-1直到我赞成) - 尽管他这样做没有证明他的答案,这就像在不显示你的工作的情况下做数学一样。


我的建议DELETE FROM

我的建议是使用.在大多数情况下,它将按照开发人员的预期执行。但是,也不是没有缺点 - 您必须显式重置表的自动增量值。若要重置表的自动增量值,必须使用另一个 DDL 语句----并且同样,不要在块中使用。它不会按预期工作。DELETE FROMDELETE FROMALTER TABLEALTER TABLEtry

如果你想要关于何时应该使用 vs 查看 TRUNCATE vs DELETE FROM 的优缺点的提示。DELETE FROMTRUNCATE


如果真的必须,请按以下步骤截断

现在,说了这么多。如果你真的想使用 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');


如何删除具有回滚/提交功能的表。

但是,如果你想要回滚/提交功能,你必须使用:(下面是Maxence答案的修改版本。DELETE FROM

$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


答案 2

以下是我正在使用的代码:

$cmd = $em->getClassMetadata($className);
$connection = $em->getConnection();
$dbPlatform = $connection->getDatabasePlatform();
$connection->beginTransaction();
try {
    $connection->query('SET FOREIGN_KEY_CHECKS=0');
    $q = $dbPlatform->getTruncateTableSql($cmd->getTableName());
    $connection->executeUpdate($q);
    $connection->query('SET FOREIGN_KEY_CHECKS=1');
    $connection->commit();
}
catch (\Exception $e) {
    $connection->rollback();
}

推荐