"There is no active transaction" 在 Doctrine 迁移中
"There is no active transaction" in Doctrine migrations
我尝试应用迁移,其中前三个用于创建 table,最后一个 - 插入数据。
当我 运行 php bin/console doctrine:migrations:migrate
它在每次迁移后给我一个错误“没有活动事务”并且停止了迁移。所以我不得不 运行 migrations:migrate
4 次。
可能是什么问题?
如果您使用 PHP 8.0,在迁移中实现“isTransactional”class 和 return false(参见 https://github.com/doctrine/DoctrineMigrationsBundle/issues/393)
对我来说,以下代码有效
public function isTransactional(): bool
{
return false;
}
此问题之前存在,但现在在 PHP 8 PDO 后可见。
I will quote a great explanation located at your
vendor/doctrine/migrations/docs/en/explanation/implicit-commits.rst
:
Implicit commits
Since PHP8, if you are using some platforms with some drivers such as
MySQL with PDO, you may get an error that you did not get before when
using this library: There is no active transaction
. It comes from
the fact that some platforms like MySQL or Oracle do not support DDL
statements (CREATE TABLE
, ALTER TABLE
, etc.) in transactions.
The issue existed before PHP 8 but is now made visible by e.g. PDO,
which now produces the above error message when this library attempts
to commit a transaction that has already been commited before.
Consider the following migration.
public function up(Schema $schema): void
{
$users = [
['name' => 'mike', 'id' => 1],
['name' => 'jwage', 'id' => 2],
['name' => 'ocramius', 'id' => 3],
];
foreach ($users as $user) {
$this->addSql('UPDATE user SET happy = true WHERE name = :name AND id = :id', $user);
}
$this->addSql('CREATE TABLE example_table (id INT AUTO_INCREMENT NOT NULL, title VARCHAR(255) DEFAULT NULL, PRIMARY KEY(id))');
}
When you run that migration, what actually happens with some platforms
is you get the updates inside an implicitly commited transaction, then
the CREATE TABLE
happens outside that transaction, and then there
is an attempt to commit an non-existent transaction.
In that sort of situation, if you still wish to get the DML statements
inside a transaction, we recommend you split the migration in 2
migrations, as follows.
final class Version20210401193057 extends AbstractMigration
{
public function up(Schema $schema): void
{
$users = [
['name' => 'mike', 'id' => 1],
['name' => 'jwage', 'id' => 2],
['name' => 'ocramius', 'id' => 3],
];
foreach ($users as $user) {
$this->addSql('UPDATE user SET happy = true WHERE name = :name AND id = :id', $user);
}
}
}
final class Version20210401193058 extends AbstractMigration
{
public function up(Schema $schema): void
{
$this->addSql('CREATE TABLE example_table (id INT AUTO_INCREMENT NOT NULL, title VARCHAR(255) DEFAULT NULL, PRIMARY KEY(id))');
}
public function isTransactional(): bool
{
return false;
}
}
Please refer to the manual of your database platform to know if you
need to do this or not.
At the moment, this library checks if there is an active transaction
before commiting it, which means you should not encouter the error
described above. It will not be the case in the next major version
though, and you should prepare for that.
To help you deal with this issue, the library features a configuration
key called transactional
. Setting it to false
will cause new
migrations to be generated with the override method above, making new
migrations non-transactional by default.
解决方案 1
按照 here 的说明禁用迁移配置文件中的参数 transactional
。
解决方案 2
这次只通过在 php bin/console doctrine:migrations:migrate
命令中添加 --all-or-nothing=0
来禁用事务迁移。
我尝试应用迁移,其中前三个用于创建 table,最后一个 - 插入数据。
当我 运行 php bin/console doctrine:migrations:migrate
它在每次迁移后给我一个错误“没有活动事务”并且停止了迁移。所以我不得不 运行 migrations:migrate
4 次。
可能是什么问题?
如果您使用 PHP 8.0,在迁移中实现“isTransactional”class 和 return false(参见 https://github.com/doctrine/DoctrineMigrationsBundle/issues/393)
对我来说,以下代码有效
public function isTransactional(): bool
{
return false;
}
此问题之前存在,但现在在 PHP 8 PDO 后可见。
I will quote a great explanation located at your
vendor/doctrine/migrations/docs/en/explanation/implicit-commits.rst
:Implicit commits
Since PHP8, if you are using some platforms with some drivers such as MySQL with PDO, you may get an error that you did not get before when using this library:
There is no active transaction
. It comes from the fact that some platforms like MySQL or Oracle do not support DDL statements (CREATE TABLE
,ALTER TABLE
, etc.) in transactions.The issue existed before PHP 8 but is now made visible by e.g. PDO, which now produces the above error message when this library attempts to commit a transaction that has already been commited before.
Consider the following migration.
public function up(Schema $schema): void
{
$users = [
['name' => 'mike', 'id' => 1],
['name' => 'jwage', 'id' => 2],
['name' => 'ocramius', 'id' => 3],
];
foreach ($users as $user) {
$this->addSql('UPDATE user SET happy = true WHERE name = :name AND id = :id', $user);
}
$this->addSql('CREATE TABLE example_table (id INT AUTO_INCREMENT NOT NULL, title VARCHAR(255) DEFAULT NULL, PRIMARY KEY(id))');
}
When you run that migration, what actually happens with some platforms is you get the updates inside an implicitly commited transaction, then the
CREATE TABLE
happens outside that transaction, and then there is an attempt to commit an non-existent transaction.In that sort of situation, if you still wish to get the DML statements inside a transaction, we recommend you split the migration in 2 migrations, as follows.
final class Version20210401193057 extends AbstractMigration
{
public function up(Schema $schema): void
{
$users = [
['name' => 'mike', 'id' => 1],
['name' => 'jwage', 'id' => 2],
['name' => 'ocramius', 'id' => 3],
];
foreach ($users as $user) {
$this->addSql('UPDATE user SET happy = true WHERE name = :name AND id = :id', $user);
}
}
}
final class Version20210401193058 extends AbstractMigration
{
public function up(Schema $schema): void
{
$this->addSql('CREATE TABLE example_table (id INT AUTO_INCREMENT NOT NULL, title VARCHAR(255) DEFAULT NULL, PRIMARY KEY(id))');
}
public function isTransactional(): bool
{
return false;
}
}
Please refer to the manual of your database platform to know if you need to do this or not.
At the moment, this library checks if there is an active transaction before commiting it, which means you should not encouter the error described above. It will not be the case in the next major version though, and you should prepare for that.
To help you deal with this issue, the library features a configuration key called
transactional
. Setting it tofalse
will cause new migrations to be generated with the override method above, making new migrations non-transactional by default.
解决方案 1
按照 here 的说明禁用迁移配置文件中的参数 transactional
。
解决方案 2
这次只通过在 php bin/console doctrine:migrations:migrate
命令中添加 --all-or-nothing=0
来禁用事务迁移。