今の職場ではマイグレーションツールの類いを全く使っておらず、メンテナンスが辛いことがあるので、以前から話に聞くFlywayを調べていてはまった障害についてメモを残す。
発生条件と現象
MySQLモードのH2DBとFlywayを組み合わせて作ったSpring Bootのアプリを起動すると以下のエラーが発生する。
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'flywayInitializer' defined in class path resource [org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration$FlywayConfiguration.class]: Invocation of init method failed; nested exception is org.flywaydb.core.internal.dbsupport.FlywaySqlScriptException:
Script failed
-------------
SQL State : 90079
Error Code : 90079
Message : スキーマ "public" が見つかりません
Schema "public" not found; SQL statement:
CREATE TABLE "public"."schema_version" (
"version_rank" INT NOT NULL,
"installed_rank" INT NOT NULL,
"version" VARCHAR(50) NOT NULL,
"description" VARCHAR(200) NOT NULL,
"type" VARCHAR(20) NOT NULL,
"script" VARCHAR(1000) NOT NULL,
"checksum" INT,
"installed_by" VARCHAR(100) NOT NULL,
"installed_on" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
"execution_time" INT NOT NULL,
"success" BOOLEAN NOT NULL
) [90079-196]
Line : 17
Statement : CREATE TABLE "public"."schema_version" (
"version_rank" INT NOT NULL,
"installed_rank" INT NOT NULL,
"version" VARCHAR(50) NOT NULL,
"description" VARCHAR(200) NOT NULL,
"type" VARCHAR(20) NOT NULL,
"script" VARCHAR(1000) NOT NULL,
"checksum" INT,
"installed_by" VARCHAR(100) NOT NULL,
"installed_on" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
"execution_time" INT NOT NULL,
"success" BOOLEAN NOT NULL
)
これはMySQLモードを指定しないH2DBでは発生しない。
調べてみると、H2DBではMySQL時のスキーマ名がPUBLIC
と大文字になってしまう?らしく、Flywayでバージョン管理テーブルを作る際にエラーが発生する模様。
解決策第1弾
とりあえずapplication.properties
にてFlywayに大文字のスキーマ名を指定する。
flyway.schemas=PUBLIC
すると状況は変わるがやはりエラー。
Caused by: org.h2.jdbc.JdbcSQLException: スキーマ "public" が見つかりません
Schema "public" not found; SQL statement:
SET SCHEMA "public" [90079-196]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:345) ~[h2-1.4.196.jar:1.4.196]
at org.h2.message.DbException.get(DbException.java:179) ~[h2-1.4.196.jar:1.4.196]
at org.h2.message.DbException.get(DbException.java:155) ~[h2-1.4.196.jar:1.4.196]
at org.h2.engine.Database.getSchema(Database.java:1755) ~[h2-1.4.196.jar:1.4.196]
at org.h2.command.dml.Set.update(Set.java:408) ~[h2-1.4.196.jar:1.4.196]
at org.h2.command.CommandContainer.update(CommandContainer.java:101) ~[h2-1.4.196.jar:1.4.196]
at org.h2.command.Command.executeUpdate(Command.java:260) ~[h2-1.4.196.jar:1.4.196]
at org.h2.jdbc.JdbcPreparedStatement.execute(JdbcPreparedStatement.java:207) ~[h2-1.4.196.jar:1.4.196]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_131]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_131]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_131]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_131]
at org.apache.tomcat.jdbc.pool.StatementFacade$StatementProxy.invoke(StatementFacade.java:114) ~[tomcat-jdbc-8.5.23.jar:na]
at com.sun.proxy.$Proxy73.execute(Unknown Source) ~[na:na]
at org.flywaydb.core.internal.dbsupport.JdbcTemplate.execute(JdbcTemplate.java:219) ~[flyway-core-3.2.1.jar:na]
at org.flywaydb.core.internal.dbsupport.h2.H2DbSupport.doSetCurrentSchema(H2DbSupport.java:70) ~[flyway-core-3.2.1.jar:na]
at org.flywaydb.core.internal.dbsupport.DbSupport.setCurrentSchema(DbSupport.java:101) ~[flyway-core-3.2.1.jar:na]
... 23 common frames omitted
解決策第2弾
これに加えてマイグレーションスクリプトの一つ目でスキーマを作成することでエラーは消える。
create schema if not exists "public";
この問題は分かりにくい上、まともな解決策とも思えないので何とかして欲しいのだが、参考ページを見る限りは望み薄という印象。
プロジェクトはこちら。
springboot-study/flyway-h2db-mysqlmode-trouble at master · orimajp/springboot-study