FlywayDB:迁移失败并显示“执行语句错误”,但手动运行迁移 SQL 代码有效

Posted

技术标签:

【中文标题】FlywayDB:迁移失败并显示“执行语句错误”,但手动运行迁移 SQL 代码有效【英文标题】:FlywayDB: Migration fails with "Error executing statement", but manually running migration SQL code works 【发布时间】:2014-05-26 08:57:01 【问题描述】:

我有一个 play framework 2.2.2 scala 应用程序并使用 play-flyway 1.0.3。

下面的迁移应该由flyway运行:

ALTER TABLE  `user_visits` ADD  `FirstSiteRequestTime` DATETIME NOT NULL ;
UPDATE `user_visits` SET `FirstSiteRequestTime`=(SELECT `Time` FROM `user_siterequests` WHERE `user_siterequests`.`Visit`=`user_visits`.`ID` ORDER BY `Time` ASC LIMIT 1) ;

所以我向表中添加一列,然后使用更新语句以编程方式填充它。

第一行执行良好,但更新语句失败

FlywaySqlScriptException: Error executing statement at line 2: UPDATE `user_visits` SET `FirstSiteRequestTime`=(SELECT `Time` FROM `user_siterequests` WHERE `user_siterequests`.`Visit`=`user_visits`.`ID` ORDER BY `Time` ASC LIMIT 1)
com.googlecode.flyway.core.command.FlywaySqlScriptException: Error executing statement at line 2: UPDATE `user_visits` SET `FirstSiteRequestTime`=(SELECT `Time` FROM `user_siterequests` WHERE `user_siterequests`.`Visit`=`user_visits`.`ID` ORDER BY `Time` ASC LIMIT 1)
com.googlecode.flyway.core.dbsupport.SqlScript.execute(SqlScript.java:92)
com.googlecode.flyway.core.resolver.sql.SqlMigrationExecutor.execute(SqlMigrationExecutor.java:72)
com.googlecode.flyway.core.command.DbMigrate$2.doInTransaction(DbMigrate.java:243)
com.googlecode.flyway.core.command.DbMigrate$2.doInTransaction(DbMigrate.java:241)
com.googlecode.flyway.core.util.jdbc.TransactionTemplate.execute(TransactionTemplate.java:72)

但是,当我使用迁移 SQL 代码并使用 phpmyadmin 运行它时,它运行良好(虽然运行需要 2-5 秒,但表很大)。

我的 mysql.log 看起来像

                  128 Query SET autocommit=0
                  128 Query ALTER TABLE  `user_visits` ADD  `FirstSiteRequestTime` DATETIME NOT NULL
140412  4:40:43   128 Query UPDATE `user_visits` SET `FirstSiteRequestTime`=(SELECT `Time` FROM `user_siterequests` WHERE `user_siterequests`.`Visit`=`user_visits`.`ID` ORDER BY `Time` ASC LIMIT 1)
140412  4:40:44   128 Query rollback
                  128 Query SET autocommit=1

flyway 是否有某种超时?日志文件显示它将查询发送到 mysql 服务器但随后回滚。为什么?如前所述,查询是正确的。当我手动运行它时它可以工作。

编辑

运行迁移后,执行并提交了 ALTER TABLE 语句(表已更改),尽管 mysql.log 说它已回滚。第二个命令真的回滚了。

我还尝试在两个迁移中拆分两个 SQL 命令。然后第一个(ALTER TABLE)运行良好,第二个失败。

edit2

这可能是某种超时问题。让它执行得更快(只更新一些行)

ALTER TABLE  `user_visits` ADD  `FirstSiteRequestTime` DATETIME NOT NULL ;
UPDATE `user_visits` SET `FirstSiteRequestTime`=(SELECT `Time` FROM `user_siterequests` WHERE `user_siterequests`.`Visit`=`user_visits`.`ID` ORDER BY `Time` ASC LIMIT 1) WHERE user_visits.id<1000;

运行正常,也在飞行路线中。

【问题讨论】:

【参考方案1】:

MySQL documentation 表示,从 MySQL 5.5.3 开始,“大多数语句”在执行前导致隐式提交也在执行后执行。这似乎包括 ALTER TABLE 语句(在 MySQL 5.5.3 及更高版本中)。

请注意,在问题显示的日志中,autocommit 已禁用。可以肯定的是,在这样的语句之间使用显式的COMMIT

ALTER TABLE  `user_visits` ADD  `FirstSiteRequestTime` DATETIME NOT NULL ;
COMMIT ;
UPDATE `user_visits` SET `FirstSiteRequestTime`=(SELECT `Time` FROM `user_siterequests` WHERE `user_siterequests`.`Visit`=`user_visits`.`ID` ORDER BY `Time` ASC LIMIT 1) ;

或将它们放在单独且连续的迁移文件中,如下所示:

文件 V1__alter_table.sql:

ALTER TABLE  `user_visits` ADD  `FirstSiteRequestTime` DATETIME NOT NULL ;

文件 V2__update_table.sql:

UPDATE `user_visits` SET `FirstSiteRequestTime`=(SELECT `Time` FROM `user_siterequests` WHERE `user_siterequests`.`Visit`=`user_visits`.`ID` ORDER BY `Time` ASC LIMIT 1) ;

【讨论】:

添加提交不会改变任何东西。同样,将其拆分为两个迁移时,第二个仍然失败(请参阅上面的编辑) 我似乎误诊了这个问题。我道歉。但至少现在,随着迁移的分离,问题应该更容易调试。请验证 Flyway 是否认为第一次迁移 (ALTER TABLE) 已成功。使用flyway info 或检查schema_version 表。如果第一次迁移失败(正如回滚似乎暗示的那样),这就是问题所在。如果成功,请检查数据库结构以确保ALTER TABLE 命令成功,然后尝试使用phpmyadmin 再次运行UPDATE 命令并验证结果。 第一次迁移成功,第二次失败。记录第二个: 256 Query SET autocommit=0 256 Query UPDATE user_visits SET FirstSiteRequestTime=(SELECT Time FROM user_siterequests WHERE user_siterequests.Visit=user_visits.@987654343BY24 Time ASC LIMIT 1) 256 查询回滚 256 查询 SET autocommit=1 在 phpmyadmin 中运行第二个仍然有效。我认为这是一个超时问题(请参阅我上面的编辑) 现在问题更清楚了。由于超时,事务似乎正在回滚。我怀疑是 MySQL 正在回滚它,但它可能是 Flyway/Java 堆栈中的东西。请验证show variables like "%timeout%"; 的输出。变量解释in this documentation page。这似乎类似于this unresolved question。 Flyway 没有设置任何特定的超时时间。这一切都发生在数据库端。

以上是关于FlywayDB:迁移失败并显示“执行语句错误”,但手动运行迁移 SQL 代码有效的主要内容,如果未能解决你的问题,请参考以下文章

原因:org.flywaydb.core.api.FlywayException:迁移失败!和 Spring Cloud 数据流

即使引发 SQLException,flywaydb 也会应用 java 迁移

flywaydb中的数据库基线版本是啥。我可以使用它从特定版本及更高版本进行迁移吗?

为啥我的 Gradle 构建失败并出现“未找到插件 [id: 'org.flywaydb.enterprise.flyway', version: '6.5.0']”错误?

FlywayDB 在迁移中忽略子文件夹

Django 迁移失败并显示“__fake__.DoesNotExist:权限匹配查询不存在”。