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']”错误?