移行のたびに実行したい一般的なクリーンアップスクリプトがあります。移行のたびにこのスクリプトを実行する良い方法はありますか(移行を行うたびにスクリプト自体を変更として含めることはできませんか?)
この質問は、Flywayの移行前および移行後のスクリプトの前に行われたことがわかります。そのときの答えは、実際にはそうではありませんでした。
過去1。5年間で答えはまったく変わりましたか?
移行のたびに実行したい一般的なクリーンアップスクリプトがあります。移行のたびにこのスクリプトを実行する良い方法はありますか(移行を行うたびにスクリプト自体を変更として含めることはできませんか?)
この質問は、Flywayの移行前および移行後のスクリプトの前に行われたことがわかります。そのときの答えは、実際にはそうではありませんでした。
過去1。5年間で答えはまったく変わりましたか?
flyway 3.0では状況が変わり、コールバックスクリプトが可能になりました。この状況では、afterMigration.sqlファイルを使用してクリーンアップを実行できます。
詳細については、 http://flywaydb.org/documentation/callbacks.htmlを参照してください。
これは変更されていません。今のところ、提案されている回避策のいずれかを使用してください。
ここでの提案とFlywayの移行前および移行後のスクリプトを確認しましたが、どの回避策(ある場合)が最も適切かわからないユースケースを指摘したいと思います。ユースケースは、開発者が作成した移行を実行する前に、dbaに復元ポイントを作成させることです。
現在、手動(非フライウェイ)移行プロセスでは、一連の移行を実行する前に、dbaが復元ポイントを作成します。移行は、復元ポイントがなくても正常に実行されます。ただし、正しいコードがない場合(たとえば、列の作成が欠落している場合)、ダウンタイムを回避し、開発者が修正に取り組む時間を確保するために、Oracleの復元ポイントにロールバックすることをお勧めします。
開発者にその復元ポイントを実行する移行を含めるように要求することは意味がないと思います。理由は次のとおりです。1。忘れる可能性があります(開発者の介入なしに自動的に発生するはずです)2。スキーマの状態によっては異なる場合があります移行を開始しているため、復元ポイントを含むものが実行されていない場合は、古い可能性があり、その間にデータが変更されている可能性があります。
復元ポイントを実行する個別の移行がある場合にも、同様の欠点があります。1.復元ポイントを実行するには、基本的に異なるバージョン番号の古い移行のコピーである新しい移行を手動で作成する必要があります。
既存のデータが大きい開発スキーマの場合、移行の開発中にスキーマをクリーンアップすることは実用的ではありません。これは、スキーマがフライウェイよりも前のものであり、最初から再作成するのにかなりの時間がかかる可能性があるためです。
開発の場合、理想的にはワークフローは次のようになります。1.復元ポイントを作成します2.移行を開発し、フライウェイを使用して実行します3.移行が必要に応じて機能しない場合は、ロールバックして復元ポイントに戻ります。
ステップ1を全面的に自動化する方法があれば、何か問題が発生してロールバックが必要になる場合を除いて、フライウェイを使用してdbaの必要性を排除できます。問題にアプローチするためのより「フライウェイ」な方法があるかもしれませんが、私が見つけた回避策は、既存のワークフローに適合していないようです。
同じ問題がありました。つまり、すべての移行の前後に常に一連のスクリプトを呼び出します。たとえば、マテリアライズドビューの削除と作成、テーブルへのアクセス許可の付与。これらのスクリプトは移行ごとに変更されませんが、実行する必要があります。
そこで、org.flywaydb.core.internal.callback.SqlScriptFlywayCallback
コールバッククラスを取得して、複数のファイルに適合させました。
flyway
私は次のパターンの哲学にとどまり、使用しようとしました。am__
またはAM__
が移行後のスクリプトで始まるファイル、で始まるファイルbi__
は情報の前などです。スクリプトを並べ替えて、正しい順序で実行されるようにします。
public class MultipleScriptPerCallback extends BaseFlywayCallback {
private static final Log LOG = LogFactory.getLog(SqlScriptFlywayCallback.class);
private static final String DELIMITER = "__";
private static final String BEFORE_CLEAN = "bc";
private static final String AFTER_CLEAN = "ac";
private static final String BEFORE_MIGRATE = "bm";
private static final String AFTER_MIGRATE = "am";
private static final String BEFORE_EACH_MIGRATE = "bem";
private static final String AFTER_EACH_MIGRATE = "aem";
private static final String BEFORE_VALIDATE = "bv";
private static final String AFTER_VALIDATE = "av";
private static final String BEFORE_BASELINE = "bb";
private static final String AFTER_BASELINE = "ab";
private static final String BEFORE_REPAIR = "br";
private static final String AFTER_REPAIR = "ar";
private static final String BEFORE_INFO = "bi";
private static final String AFTER_INFO = "ai";
private static final List<String> ALL_CALLBACKS = Arrays.asList(BEFORE_CLEAN, AFTER_CLEAN, BEFORE_MIGRATE, BEFORE_EACH_MIGRATE,
AFTER_EACH_MIGRATE, AFTER_MIGRATE, BEFORE_VALIDATE, AFTER_VALIDATE, BEFORE_BASELINE, AFTER_BASELINE, BEFORE_REPAIR,
AFTER_REPAIR, BEFORE_INFO, AFTER_INFO);
private Map<String, List<SqlScript>> scripts;
@Override
public void setFlywayConfiguration(FlywayConfiguration flywayConfiguration) {
super.setFlywayConfiguration(flywayConfiguration);
if (scripts == null) {
scripts = registerScripts(flywayConfiguration);
}
}
private Map<String, List<SqlScript>> registerScripts(FlywayConfiguration flywayConfiguration) {
Map<String, List<SqlScript>> scripts = new HashMap<>();
for (String callback : ALL_CALLBACKS) {
scripts.put(callback, new ArrayList<SqlScript>());
}
LOG.debug(String.format("%s - Scanning for Multiple SQL callbacks ...", getClass().getSimpleName()));
Locations locations = new Locations(flywayConfiguration.getLocations());
Scanner scanner = new Scanner(flywayConfiguration.getClassLoader());
String sqlMigrationSuffix = flywayConfiguration.getSqlMigrationSuffix();
DbSupport dbSupport = dbSupport(flywayConfiguration);
PlaceholderReplacer placeholderReplacer = createPlaceholderReplacer();
String encoding = flywayConfiguration.getEncoding();
for (Location location : locations.getLocations()) {
Resource[] resources;
try {
resources = scanner.scanForResources(location, "", sqlMigrationSuffix);
} catch (FlywayException e) {
// Ignore missing locations
continue;
}
for (Resource resource : resources) {
String key = extractKeyFromFileName(resource);
if (scripts.keySet().contains(key)) {
LOG.debug(getClass().getSimpleName() + " - found script " + resource.getFilename() + " from location: " + location);
List<SqlScript> sqlScripts = scripts.get(key);
sqlScripts.add(new SqlScript(dbSupport, resource, placeholderReplacer, encoding));
}
}
}
LOG.info(getClass().getSimpleName() + " - scripts registered: " + prettyPrint(scripts));
return scripts;
}
private String prettyPrint(Map<String, List<SqlScript>> scripts) {
StringBuilder prettyPrint = new StringBuilder();
boolean isFirst = true;
for (String key : scripts.keySet()) {
if (!isFirst) {
prettyPrint.append("; ");
}
prettyPrint.append(key).append("=").append("[").append(prettyPrint(scripts.get(key))).append("]");
isFirst = false;
}
return prettyPrint.toString();
}
private String prettyPrint(List<SqlScript> scripts) {
StringBuilder prettyPrint = new StringBuilder();
boolean isFirst = true;
for (SqlScript script : scripts) {
if (!isFirst) {
prettyPrint.append(", ");
}
prettyPrint.append(script.getResource().getFilename());
isFirst = false;
}
return prettyPrint.toString();
}
private String extractKeyFromFileName(Resource resource) {
String filename = resource.getFilename();
eturn filename.substring(0, (!filename.contains(DELIMITER)) ? 0 : filename.indexOf(DELIMITER)).toLowerCase();
}
private DbSupport dbSupport(FlywayConfiguration flywayConfiguration) {
Connection connectionMetaDataTable = JdbcUtils.openConnection(flywayConfiguration.getDataSource());
return DbSupportFactory.createDbSupport(connectionMetaDataTable, true);
}
/**
* @return A new, fully configured, PlaceholderReplacer.
*/
private PlaceholderReplacer createPlaceholderReplacer() {
if (flywayConfiguration.isPlaceholderReplacement()) {
return
new PlaceholderReplacer(flywayConfiguration.getPlaceholders(), flywayConfiguration.getPlaceholderPrefix(),
flywayConfiguration.getPlaceholderSuffix());
}
return PlaceholderReplacer.NO_PLACEHOLDERS;
}
@Override
public void beforeClean(Connection connection) {
execute(BEFORE_CLEAN, connection);
}
@Override
public void afterClean(Connection connection) {
execute(AFTER_CLEAN, connection);
}
@Override
public void beforeMigrate(Connection connection) {
execute(BEFORE_MIGRATE, connection);
}
@Override
public void afterMigrate(Connection connection) {
execute(AFTER_MIGRATE, connection);
}
@Override
public void beforeEachMigrate(Connection connection, MigrationInfo info) {
execute(BEFORE_EACH_MIGRATE, connection);
}
@Override
public void afterEachMigrate(Connection connection, MigrationInfo info) {
execute(AFTER_EACH_MIGRATE, connection);
}
@Override
public void beforeValidate(Connection connection) {
execute(BEFORE_VALIDATE, connection);
}
@Override
public void afterValidate(Connection connection) {
execute(AFTER_VALIDATE, connection);
}
@Override
public void beforeBaseline(Connection connection) {
execute(BEFORE_BASELINE, connection);
}
@Override
public void afterBaseline(Connection connection) {
execute(AFTER_BASELINE, connection);
}
@Override
public void beforeRepair(Connection connection) {
execute(BEFORE_REPAIR, connection);
}
@Override
public void afterRepair(Connection connection) {
execute(AFTER_REPAIR, connection);
}
@Override
public void beforeInfo(Connection connection) {
execute(BEFORE_INFO, connection);
}
@Override
public void afterInfo(Connection connection) {
execute(AFTER_INFO, connection);
}
private void execute(String key, Connection connection) {
List<SqlScript> sqlScripts = scripts.get(key);
LOG.debug(String.format("%s - sqlscript: %s for key: %s", getClass().getSimpleName(), sqlScripts, key));
Collections.sort(sqlScripts, new SqlScriptLexicalComparator());
for (SqlScript script : sqlScripts) {
executeScript(key, connection, script);
}
}
//Not private for testing
void executeScript(String key, Connection connection, SqlScript script) {
LOG.info(String.format("%s - Executing SQL callback: %s : %s", getClass().getSimpleName(), key,
script.getResource().getFilename()));
script.execute(new JdbcTemplate(connection, 0));
}
//Not private for testing
static final class SqlScriptLexicalComparator implements Comparator<SqlScript> {
@Override
public int compare(SqlScript o1, SqlScript o2) {
return Collator.getInstance().compare(o1.getResource().getFilename(), o2.getResource().getFilename());
}
}
}