Migration flyway:每次迁移后运行的通用脚本
我有一个通用的清理脚本,我想在每次迁移后运行它。是否有一种在每次迁移后运行此脚本的好方法(除了在每次迁移时将脚本本身作为一个更改包含在内?) 我知道这个问题以前在这里被问过,当时的答案是不,不是真的Migration flyway:每次迁移后运行的通用脚本,migration,flyway,Migration,Flyway,我有一个通用的清理脚本,我想在每次迁移后运行它。是否有一种在每次迁移后运行此脚本的好方法(除了在每次迁移时将脚本本身作为一个更改包含在内?) 我知道这个问题以前在这里被问过,当时的答案是不,不是真的 答案在过去的1.5年里有没有改变?这一点没有改变。现在就使用任何建议的变通方法。我已经看过这里的建议,并想指出一个我看不出哪种变通方法(如果有的话)最适用的用例。用例是让dba在运行开发人员创建的迁移之前创建一个恢复点 现在,通过我们的手动(非flyway)迁移过程,dba会在运行一组迁移之前创建一
答案在过去的1.5年里有没有改变?这一点没有改变。现在就使用任何建议的变通方法。我已经看过这里的建议,并想指出一个我看不出哪种变通方法(如果有的话)最适用的用例。用例是让dba在运行开发人员创建的迁移之前创建一个恢复点 现在,通过我们的手动(非flyway)迁移过程,dba会在运行一组迁移之前创建一个恢复点。迁移在没有恢复点的情况下可以正常运行。但是如果他们没有正确的代码(比如缺少创建列),通常最好回滚到oracle恢复点,以避免停机,并让开发人员有时间进行修复 我认为,要求开发人员包含一个能够实现该恢复点的迁移是没有意义的,因为: 1.他们可能会忘记(应该自动发生,而不需要开发人员干预) 2.根据架构的状态,可能会有不同的开始迁移,因此,如果包含还原点的迁移未运行,则可能是旧迁移,并且在此期间数据可能已更改 使用单独的迁移进行恢复点迁移也有类似的缺点: 1.他们必须手动创建一个新迁移,该迁移本质上是一个旧迁移的副本,具有不同的版本号才能执行恢复点 对于具有大量现有数据的开发模式,在开发迁移时清除模式是不切实际的,因为它早于flyway,可能需要大量时间从头开始重新创建 对于开发,理想情况下,工作流如下所示: 1.创建还原点 2.开发迁移,使用flyway运行 3.如果迁移未按要求工作,请回滚到还原点
如果有一种全面自动化步骤1的方法,它将允许我们使用flyway并消除对dba的需求,除非出现问题,需要回滚。可能有一种更为“flyway”的方法来解决这个问题,但我发现的解决方法似乎不适合我们现有的工作流程。使用flyway 3.0,情况已经改变,现在可以使用回调脚本。在这种情况下,可以使用afterMigration.sql文件进行清理
有关更多信息,请参阅。我们遇到了相同的问题。也就是说,每次迁移前后都要调用一组脚本。例如,删除和创建物化视图,授予表权限。 这些脚本不会随着迁移而改变,但它们需要执行 因此,我采用了
org.flywaydb.core.internal.callback.SqlScriptFlywayCallback
回调类,并将其改编为多个文件
我试图保持flyway
的理念,并使用以下模式。
以am\uuu
或am\uu
开头的文件是迁移后脚本,以bi\uu
开头的文件是迁移前信息,依此类推。
我对脚本进行排序,以便它们按正确的顺序执行
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());
}
}
public类MultipleScriptPerCallback扩展了BaseFlywayCallback{
私有静态最终日志日志=LogFactory.getLog(SqlScriptFlywayCallback.class);
私有静态最终字符串分隔符=“\uuuu”;
_CLEAN=“bc”之前的私有静态最终字符串;
_CLEAN=“ac”之后的私有静态最终字符串;
_MIGRATE=“bm”之前的私有静态最终字符串;
_MIGRATE=“am”之后的私有静态最终字符串;
每个\u MIGRATE=“bem”之前的私有静态最终字符串;
每次\u MIGRATE=“aem”后的私有静态最终字符串;
_VALIDATE=“bv”之前的私有静态最终字符串;
_VALIDATE=“av”之后的私有静态最终字符串;
_BASELINE=“bb”之前的私有静态最终字符串;
_BASELINE=“ab”之后的私有静态最终字符串;
_REPAIR=“br”之前的私有静态最终字符串;
_REPAIR=“ar”后的私有静态最终字符串;
_INFO=“bi”前面的私有静态最终字符串;
_INFO=“ai”之后的私有静态最终字符串;
private static final List ALL_CALLBACKS=Arrays.asList(在_CLEAN之前、之后、迁移之前、每次迁移之前、,
每次移植后、移植后、验证前、验证后、基线前、基线后、修复前,
维修后、信息前、信息后);
私有地图脚本;
@凌驾
公共无效设置FlywayConfiguration(FlywayConfiguration FlywayConfiguration){
super.setFlywayConfiguration(flywayConfiguration);
如果(脚本==null){
脚本=注册表脚本(flywayConfiguration);
}
}
专用地图注册表脚本(FlywayConfiguration FlywayConfiguration){
Map scripts=newhashmap();
for(字符串回调:所有_回调){
put(回调,newarraylist());
}
LOG.debug(String.format(“%s-扫描多个SQL回调…”),getClass().getSimpleName());
位置=新位置(flywayConfiguration.getLocations());
Scanner Scanner=新扫描仪(flywayConfiguration.getClassLoader());
字符串sqlMigrationSuffix=flywayConfiguration.getSqlMigrationSuffix();
DbSupport DbSupport=DbSupport(航路配置);
PlaceholderReplacer=createPlaceholderReplacer();
字符串编码=flywayConfiguration.getEncoding();
对于(位置:locations.getLocations()){
资源[]资源;
试一试{
resources=scanner.scanForResources(位置“”,sqlMigrationSuffix);
}捕获(飞行路线例外e){
//忽略丢失的位置
继续;
}
F