我认为我需要使用Doctrine2构建一个本机查询来截断表。
$emptyRsm = new \Doctrine\ORM\Query\ResultSetMapping();
$sql = 'TRUNCATE TABLE Article';
$query = em()->createNativeQuery($sql, $emptyRsm);
$query->execute();
这会导致错误
SQLSTATE[HY000]: General error
我需要更改我的代码才能使其正常工作吗?
我认为我需要使用Doctrine2构建一个本机查询来截断表。
$emptyRsm = new \Doctrine\ORM\Query\ResultSetMapping();
$sql = 'TRUNCATE TABLE Article';
$query = em()->createNativeQuery($sql, $emptyRsm);
$query->execute();
这会导致错误
SQLSTATE[HY000]: General error
我需要更改我的代码才能使其正常工作吗?
在任何RDBMS中截断表时要小心,特别是如果您想使用显式事务进行提交/回滚功能。请阅读此答案的“我的建议”部分。
truncate table语句是数据定义语言(DDL)语句,因此截断表语句会在执行时向数据库触发隐式COMMIT
。如果执行TABLE TRUNCATE
,则数据库将被隐式提交--即使TABLE TRUNCATE
在START TRANSACTION
语句内,您的表也将被截断,ROLLBACK
将无法恢复它。
由于截断表语句执行隐式提交,Maxence的答案并不像预期那样工作(但它不是错误的,因为问题是“如何截断表格”)。他的答案不按预期工作,因为它在try
块中截断了表,并假设如果出现问题,则可以在catch
块中还原该表。这是一个不正确的假设。
ChrisAelbrecht无法使Maxence的解决方案正常工作,因为即使截断表语句在显式事务中,也无法回滚它。
user2130519不幸地因提供正确答案而被投票否定(直到我投了赞成票),虽然他没有为自己的答案提供解释,但这就像不展示你的工作就做数学一样。
DELETE FROM
我的建议是使用DELETE FROM
。在大多数情况下,它将按开发人员的预期执行。但是,DELETE FROM
也不是没有缺点--您必须显式重置该表的自动增量值。要重置该表的自动增量值,必须使用另一个DDL语句--ALTER TABLE
--并且不要在try
块中使用ALTER TABLE
。它不会按预期工作。
如果您想了解何时应该使用DELETE FROM
vs 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
。
$em->clear();
,否则您有可能会将旧记录插入到数据库中。 - vvolkovTRUNCATE 在处理表中的数据时是安全的:如果周围的事务没有提交,则截断将被安全地回滚。
- Jan Mares这是我正在使用的代码:
$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();
}
$em->getConnection()->query('START TRANSACTION;SET FOREIGN_KEY_CHECKS=0; TRUNCATE table1; TRUNCATE table2;SET FOREIGN_KEY_CHECKS=1; COMMIT;')
翻译:这段代码执行了MySQL数据库的事务操作,先启动一个事务(START TRANSACTION),然后暂时禁用外键约束(SET FOREIGN_KEY_CHECKS=0),接着清空table1和table2两个表的数据(TRUNCATE table1; TRUNCATE table2;),最后再开启外键约束(SET FOREIGN_KEY_CHECKS=1),并提交整个事务(COMMIT)。 - E Ciotti或者您可以尝试这个:
$this->getEm()->createQuery('DELETE AcmeBundle:Post p')->execute();
这是单元测试中从trait中截取示例的方法。
/**
* Cleanup any needed table abroad TRUNCATE SQL function
*
* @param string $className (example: App\Entity\User)
* @param EntityManager $em
* @return bool
*/
private function truncateTable (string $className, EntityManager $em): bool {
$cmd = $em->getClassMetadata($className);
$connection = $em->getConnection();
$connection->beginTransaction();
try {
$connection->query('SET FOREIGN_KEY_CHECKS=0');
$connection->query('TRUNCATE TABLE '.$cmd->getTableName());
$connection->query('SET FOREIGN_KEY_CHECKS=1');
$connection->commit();
$em->flush();
} catch (\Exception $e) {
try {
fwrite(STDERR, print_r('Can\'t truncate table ' . $cmd->getTableName() . '. Reason: ' . $e->getMessage(), TRUE));
$connection->rollback();
return false;
} catch (ConnectionException $connectionException) {
fwrite(STDERR, print_r('Can\'t rollback truncating table ' . $cmd->getTableName() . '. Reason: ' . $connectionException->getMessage(), TRUE));
return false;
}
}
return true;
}
$em->flush()
,您可能会在下一个对Doctrine的查询中遇到问题。fwrite(STDERR, print_r(...
更改为您的记录器服务可以使用的内容。/**
* @return int
*/
public function deleteAll(): int
{
$qb = $this->createQueryBuilder('t');
$qb->delete();
return $qb->getQuery()->getSingleScalarResult() ?? 0;
}