flyway是一款用来管理数据库版本的工具框架
一, 添加依赖
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
二, 编写配置类
MySQLDatabase
/*
* Copyright (C) Red Gate Software Ltd 2010-2021
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.flywaydb.core.internal.database.mysql;
import lombok.CustomLog;
import lombok.extern.slf4j.Slf4j;
import org.flywaydb.core.api.FlywayException;
import org.flywaydb.core.api.MigrationType;
import org.flywaydb.core.api.MigrationVersion;
import org.flywaydb.core.api.configuration.Configuration;
import org.flywaydb.core.internal.database.base.Database;
import org.flywaydb.core.internal.database.base.BaseDatabaseType;
import org.flywaydb.core.internal.database.base.Table;
import org.flywaydb.core.internal.database.mysql.mariadb.MariaDBDatabaseType;
import org.flywaydb.core.internal.jdbc.JdbcConnectionFactory;
import org.flywaydb.core.internal.jdbc.JdbcTemplate;
import org.flywaydb.core.internal.jdbc.StatementInterceptor;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Slf4j
public class MySQLDatabase extends Database<MySQLConnection> {
// See https://mariadb.com/kb/en/version/
private static final Pattern MARIADB_VERSION_PATTERN = Pattern.compile("(\\d+\\.\\d+)\\.\\d+(-\\d+)*-MariaDB(-\\w+)*");
private static final Pattern MARIADB_WITH_MAXSCALE_VERSION_PATTERN = Pattern.compile("(\\d+\\.\\d+)\\.\\d+(-\\d+)* (\\d+\\.\\d+)\\.\\d+(-\\d+)*-maxscale(-\\w+)*");
private static final Pattern MYSQL_VERSION_PATTERN = Pattern.compile("(\\d+\\.\\d+)\\.\\d+\\w*");
/**
* Whether this is a Percona XtraDB Cluster in strict mode.
*/
private final boolean pxcStrict;
/**
* Whether this database is enforcing GTID consistency.
*/
private final boolean gtidConsistencyEnforced;
/**
* Whether the event scheduler table is queryable.
*/
final boolean eventSchedulerQueryable;
public MySQLDatabase(Configuration configuration, JdbcConnectionFactory jdbcConnectionFactory, StatementInterceptor statementInterceptor) {
super(configuration, jdbcConnectionFactory, statementInterceptor);
JdbcTemplate jdbcTemplate = new JdbcTemplate(rawMainJdbcConnection, databaseType);
pxcStrict = isMySQL() && isRunningInPerconaXtraDBClusterWithStrictMode(jdbcTemplate);
gtidConsistencyEnforced = isMySQL() && isRunningInGTIDConsistencyMode(jdbcTemplate);
eventSchedulerQueryable = false;
}
private static boolean isEventSchedulerQueryable(JdbcTemplate jdbcTemplate) {
try {
// Attempt query
jdbcTemplate.queryForString("SELECT event_name FROM information_schema.events LIMIT 1");
return true;
} catch (SQLException e) {
log.debug("Detected unqueryable MariaDB event scheduler, most likely due to it being OFF or DISABLED.");
return false;
}
}
static boolean isRunningInPerconaXtraDBClusterWithStrictMode(JdbcTemplate jdbcTemplate) {
try {
String pcx_strict_mode = jdbcTemplate.queryForString(
"select VARIABLE_VALUE from performance_schema.global_variables"
+ " where variable_name = 'pxc_strict_mode'");
if ("ENFORCING".equals(pcx_strict_mode) || "MASTER".equals(pcx_strict_mode)) {
log.debug("Detected Percona XtraDB Cluster in strict mode");
return true;
}
} catch (SQLException e) {
log.debug("Unable to detect whether we are running in a Percona XtraDB Cluster. Assuming not to be.");
}
return false;
}
static boolean isRunningInGTIDConsistencyMode(JdbcTemplate jdbcTemplate) {
try {
String gtidConsistency = jdbcTemplate.queryForString("SELECT @@GLOBAL.ENFORCE_GTID_CONSISTENCY");
if ("ON".equals(gtidConsistency)) {
log.debug("Detected GTID consistency being enforced");
return true;
}
} catch (SQLException e) {
log.debug("Unable to detect whether database enforces GTID consistency. Assuming not.");
}
return false;
}
boolean isMySQL() {
return databaseType instanceof MySQLDatabaseType;
}
boolean isMariaDB() {
return databaseType instanceof MariaDBDatabaseType;
}
boolean isPxcStrict() {
return pxcStrict;
}
/*
* CREATE TABLE ... AS SELECT ... cannot be used in three scenarios:
* - Percona XtraDB Cluster in strict mode doesn't support it
* - TiDB doesn't support it (overridden elsewhere)
* - When GTID consistency is being enforced. Note that if GTID_MODE is ON, then ENFORCE_GTID_CONSISTENCY is
* necessarily ON as well.
*/
protected boolean isCreateTableAsSelectAllowed() {
return !pxcStrict && !gtidConsistencyEnforced;
}
@Override
public String getRawCreateScript(Table table, boolean baseline) {
String tablespace =
configuration.getTablespace() == null
? ""
: " TABLESPACE \"" + configuration.getTablespace() + "\"";
String baselineMarker = "";
if (baseline) {
if (isCreateTableAsSelectAllowed()) {
baselineMarker = " AS SELECT" +
" 1 as \"installed_rank\"," +
" '" + configuration.getBaselineVersion() + "' as \"version\"," +
" '" + configuration.getBaselineDescription() + "' as \"description\"," +
" '" + MigrationType.BASELINE + "' as \"type\"," +
" '" + configuration.getBaselineDescription() + "' as \"script\"," +
" NULL as \"checksum\"," +
" '" + getInstalledBy() + "' as \"installed_by\"," +
" CURRENT_TIMESTAMP as \"installed_on\"," +
" 0 as \"execution_time\"," +
" TRUE as \"success\"\n";
} else {
// Revert to regular insert, which unfortunately is not safe in concurrent scenarios
// due to MySQL implicit commits after DDL statements.
baselineMarker = ";\n" + getBaselineStatement(table);
}
}
return "CREATE TABLE " + table + " (\n" +
" `installed_rank` INT NOT NULL,\n" +
" `version` VARCHAR(50),\n" +
" `description` VARCHAR(200) NOT NULL,\n" +
" `type` VARCHAR(20) NOT NULL,\n" +
" `script` VARCHAR(1000) NOT NULL,\n" +
" `checksum` INT,\n" +
" `installed_by` VARCHAR(100) NOT NULL,\n" +
" `installed_on` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\n" +
" `execution_time` INT NOT NULL,\n" +
" `success` BOOL NOT NULL,\n" +
" CONSTRAINT " + getConstraintName(table.getName()) + " PRIMARY KEY (`installed_rank`)\n" +
")" + tablespace + " ENGINE=InnoDB" +
baselineMarker +
";\n" +
"CREATE INDEX `" + table.getName() + "_s_idx` ON " + table + " (`success`);";
}
protected String getConstraintName(String tableName) {
return "`" + tableName + "_pk`";
}
@Override
protected MySQLConnection doGetConnection(Connection connection) {
return new MySQLConnection(this, connection);
}
@Override
protected MigrationVersion determineVersion() {
// Ignore the version from the JDBC metadata and use the version returned by the database since proxies such as
// Azure or ProxySQL return incorrect versions
String selectVersionOutput = BaseDatabaseType.getSelectVersionOutput(rawMainJdbcConnection);
if (databaseType instanceof MariaDBDatabaseType) {
return extractMariaDBVersionFromString(selectVersionOutput);
}
return extractMySQLVersionFromString(selectVersionOutput);
}
static MigrationVersion extractMySQLVersionFromString(String selectVersionOutput) {
return extractVersionFromString(selectVersionOutput, MYSQL_VERSION_PATTERN);
}
static MigrationVersion extractMariaDBVersionFromString(String selectVersionOutput) {
return extractVersionFromString(selectVersionOutput, MARIADB_VERSION_PATTERN, MARIADB_WITH_MAXSCALE_VERSION_PATTERN);
}
/*
* Given a version string that may contain unwanted text, extract out the version part.
*/
private static MigrationVersion extractVersionFromString(String versionString, Pattern... patterns) {
for (Pattern pattern : patterns) {
Matcher matcher = pattern.matcher(versionString);
if (matcher.find()) {
return MigrationVersion.fromVersion(matcher.group(1));
}
}
throw new FlywayException("Unable to determine version from '" + versionString + "'");
}
@Override
public final void ensureSupported() {
ensureDatabaseIsRecentEnough("5.1");
if (databaseType instanceof MariaDBDatabaseType) {
ensureDatabaseNotOlderThanOtherwiseRecommendUpgradeToFlywayEdition("10.3", org.flywaydb.core.internal.license.Edition.ENTERPRISE);
recommendFlywayUpgradeIfNecessary("10.6");
} else {
ensureDatabaseNotOlderThanOtherwiseRecommendUpgradeToFlywayEdition("8.0", org.flywaydb.core.internal.license.Edition.ENTERPRISE);
recommendFlywayUpgradeIfNecessary("8.0");
}
}
@Override
protected String doGetCurrentUser() throws SQLException {
return getMainConnection().getJdbcTemplate().queryForString("SELECT SUBSTRING_INDEX(USER(),'@',1)");
}
@Override
public boolean supportsDdlTransactions() {
return false;
}
@Override
public boolean supportsChangingCurrentSchema() {
return true;
}
@Override
public String getBooleanTrue() {
return "1";
}
@Override
public String getBooleanFalse() {
return "0";
}
@Override
public String doQuote(String identifier) {
return "`" + identifier + "`";
}
@Override
public boolean catalogIsSchema() {
return true;
}
@Override
public boolean useSingleConnection() {
return !pxcStrict;
}
}
MySQLNamedLockTemplate
/*
* Copyright (C) Red Gate Software Ltd 2010-2021
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.flywaydb.core.internal.database.mysql;
import java.sql.SQLException;
import java.util.concurrent.Callable;
import lombok.extern.slf4j.Slf4j;
import org.flywaydb.core.api.FlywayException;
import org.flywaydb.core.internal.exception.FlywaySqlException;
import org.flywaydb.core.internal.jdbc.JdbcTemplate;
/**
* Spring-like template for executing with MySQL named locks.
*/
@Slf4j
public class MySQLNamedLockTemplate {
/**
* The connection for the named lock.
*/
private final JdbcTemplate jdbcTemplate;
private final String lockName;
/**
* Creates a new named lock template for this connection.
*
* @param jdbcTemplate The jdbcTemplate for the connection.
* @param discriminator A number to discriminate between locks.
*/
MySQLNamedLockTemplate(JdbcTemplate jdbcTemplate, int discriminator) {
this.jdbcTemplate = jdbcTemplate;
lockName = "Flyway-" + discriminator;
}
/**
* Executes this callback with a named lock.
*
* @param callable The callback to execute.
* @return The result of the callable code.
*/
public <T> T execute(Callable<T> callable) {
try {
lock();
return callable.call();
} catch (SQLException e) {
throw new FlywaySqlException("Unable to acquire MySQL named lock: " + lockName, e);
} catch (Exception e) {
RuntimeException rethrow;
if (e instanceof RuntimeException) {
rethrow = (RuntimeException) e;
} else {
rethrow = new FlywayException(e);
}
throw rethrow;
} finally {
try {
//FIXME ocean base 没有GET_LOCK 需要通过其他方式来实现flyway锁
if (1 == 1) {
} else {
jdbcTemplate.execute("SELECT RELEASE_LOCK('" + lockName + "')");
}
} catch (SQLException e) {
log.error("Unable to release MySQL named lock: " + lockName, e);
}
}
}
private void lock() throws SQLException {
while (!tryLock()) {
try {
Thread.sleep(100L);
} catch (InterruptedException e) {
throw new FlywayException(
"Interrupted while attempting to acquire MySQL named lock: " + lockName, e);
}
}
}
private boolean tryLock() throws SQLException {
//FIXME ocean base 没有GET_LOCK 需要通过其他方式来实现flyway锁
if (1 == 1) {
return true;
}
return jdbcTemplate.queryForInt("SELECT GET_LOCK(?,10)", lockName) == 1;
}
}
Databse类
/*
* Copyright (C) Red Gate Software Ltd 2010-2021
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.flywaydb.core.internal.database.base;
import lombok.CustomLog;
import lombok.extern.slf4j.Slf4j;
import org.flywaydb.core.api.MigrationType;
import org.flywaydb.core.api.MigrationVersion;
import org.flywaydb.core.api.configuration.Configuration;
import org.flywaydb.core.internal.database.DatabaseType;
import org.flywaydb.core.internal.exception.FlywayDbUpgradeRequiredException;
import org.flywaydb.core.internal.exception.FlywaySqlException;
import org.flywaydb.core.internal.jdbc.JdbcConnectionFactory;
import org.flywaydb.core.internal.jdbc.JdbcTemplate;
import org.flywaydb.core.internal.jdbc.StatementInterceptor;
import org.flywaydb.core.internal.license.Edition;
import org.flywaydb.core.internal.license.FlywayEditionUpgradeRequiredException;
import org.flywaydb.core.internal.resource.StringResource;
import org.flywaydb.core.internal.sqlscript.Delimiter;
import org.flywaydb.core.internal.sqlscript.SqlScript;
import org.flywaydb.core.internal.sqlscript.SqlScriptFactory;
import org.flywaydb.core.internal.util.AbbreviationUtils;
import java.io.Closeable;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
/**
* Abstraction for database-specific functionality.
*/
@Slf4j
public abstract class Database<C extends Connection> implements Closeable {
protected final DatabaseType databaseType;
protected final Configuration configuration;
protected final StatementInterceptor statementInterceptor;
protected final JdbcConnectionFactory jdbcConnectionFactory;
protected final DatabaseMetaData jdbcMetaData;
protected JdbcTemplate jdbcTemplate;
private C migrationConnection;
private C mainConnection;
/**
* The main JDBC connection, without any wrapping.
*/
protected final java.sql.Connection rawMainJdbcConnection;
/**
* The 'major.minor' version of this database.
*/
private MigrationVersion version;
/**
* The user who applied the migrations.
*/
private String installedBy;
public Database(Configuration configuration, JdbcConnectionFactory jdbcConnectionFactory, StatementInterceptor statementInterceptor) {
this.databaseType = jdbcConnectionFactory.getDatabaseType();
this.configuration = configuration;
this.rawMainJdbcConnection = jdbcConnectionFactory.openConnection();
try {
this.jdbcMetaData = rawMainJdbcConnection.getMetaData();
} catch (SQLException e) {
throw new FlywaySqlException("Unable to get metadata for connection", e);
}
this.jdbcTemplate = new JdbcTemplate(rawMainJdbcConnection, databaseType);
this.jdbcConnectionFactory = jdbcConnectionFactory;
this.statementInterceptor = statementInterceptor;
}
/**
* Retrieves a Flyway Connection for this JDBC connection.
*/
private C getConnection(java.sql.Connection connection) {
return doGetConnection(connection);
}
/**
* Retrieves a Flyway Connection for this JDBC connection.
*/
protected abstract C doGetConnection(java.sql.Connection connection);
/**
* Ensure Flyway supports this version of this database.
*/
public abstract void ensureSupported();
/**
* @return The 'major.minor' version of this database.
*/
public final MigrationVersion getVersion() {
if (version == null) {
version = determineVersion();
}
return version;
}
protected final void ensureDatabaseIsRecentEnough(String oldestSupportedVersion) {
/* if (!getVersion().isAtLeast(oldestSupportedVersion)) {
throw new FlywayDbUpgradeRequiredException(
databaseType,
computeVersionDisplayName(getVersion()),
computeVersionDisplayName(MigrationVersion.fromVersion(oldestSupportedVersion)));
}*/
}
/**
* Ensure this database it at least as recent as this version otherwise suggest upgrade to this higher edition of
* Flyway.
*/
protected final void ensureDatabaseNotOlderThanOtherwiseRecommendUpgradeToFlywayEdition(String oldestSupportedVersionInThisEdition,
Edition editionWhereStillSupported) {
/* if (!getVersion().isAtLeast(oldestSupportedVersionInThisEdition)) {
throw new FlywayEditionUpgradeRequiredException(
editionWhereStillSupported,
databaseType,
computeVersionDisplayName(getVersion()));
}*/
}
protected final void recommendFlywayUpgradeIfNecessary(String newestSupportedVersion) {
if (getVersion().isNewerThan(newestSupportedVersion)) {
recommendFlywayUpgrade(newestSupportedVersion);
}
}
protected final void recommendFlywayUpgradeIfNecessaryForMajorVersion(String newestSupportedVersion) {
if (getVersion().isMajorNewerThan(newestSupportedVersion)) {
recommendFlywayUpgrade(newestSupportedVersion);
}
}
protected final void notifyDatabaseIsNotFormallySupported() {
String message = "Support for " + databaseType + " is provided only on a community-led basis, and is not formally supported by Redgate";
log.warn(message);
}
private void recommendFlywayUpgrade(String newestSupportedVersion) {
String message = "Flyway upgrade recommended: " + databaseType + " " + computeVersionDisplayName(getVersion())
+ " is newer than this version of Flyway and support has not been tested."
+ " The latest supported version of " + databaseType + " is " + newestSupportedVersion + ".";
log.warn(message);
}
/**
* Compute the user-friendly display name for this database version.
*/
protected String computeVersionDisplayName(MigrationVersion version) {
return version.getVersion();
}
public Delimiter getDefaultDelimiter() {
return Delimiter.SEMICOLON;
}
/**
* @return The name of the database, by default as determined by JDBC.
*/
public final String getCatalog() {
try {
return doGetCatalog();
} catch (SQLException e) {
throw new FlywaySqlException("Error retrieving the database name", e);
}
}
protected String doGetCatalog() throws SQLException {
return getMainConnection().getJdbcConnection().getCatalog();
}
public final String getCurrentUser() {
try {
return doGetCurrentUser();
} catch (SQLException e) {
throw new FlywaySqlException("Error retrieving the database user", e);
}
}
protected String doGetCurrentUser() throws SQLException {
return jdbcMetaData.getUserName();
}
public abstract boolean supportsDdlTransactions();
public abstract boolean supportsChangingCurrentSchema();
/**
* @return The representation of the value {@code true} in a boolean column.
*/
public abstract String getBooleanTrue();
/**
* @return The representation of the value {@code false} in a boolean column.
*/
public abstract String getBooleanFalse();
/**
* Quotes these identifiers for use in SQL queries. Multiple identifiers will be quoted and separated by a dot.
*/
public final String quote(String... identifiers) {
StringBuilder result = new StringBuilder();
boolean first = true;
for (String identifier : identifiers) {
if (!first) {
result.append(".");
}
first = false;
result.append(doQuote(identifier));
}
return result.toString();
}
/**
* Quotes this identifier for use in SQL queries.
*/
protected abstract String doQuote(String identifier);
/**
* @return {@code true} if this database uses a catalog to represent a schema, or {@code false} if a schema is
* simply a schema.
*/
public abstract boolean catalogIsSchema();
/**
* @return Whether to use a single connection for both schema history table management and applying migrations.
*/
public boolean useSingleConnection() {
return false;
}
public DatabaseMetaData getJdbcMetaData() {
return jdbcMetaData;
}
/**
* @return The main connection used to manipulate the schema history.
*/
public final C getMainConnection() {
if (mainConnection == null) {
this.mainConnection = getConnection(rawMainJdbcConnection);
}
return mainConnection;
}
/**
* @return The migration connection used to apply migrations.
*/
public final C getMigrationConnection() {
if (migrationConnection == null) {
if (useSingleConnection()) {
this.migrationConnection = getMainConnection();
} else {
this.migrationConnection = getConnection(jdbcConnectionFactory.openConnection());
}
}
return migrationConnection;
}
/**
* @return The major and minor version of the database.
*/
protected MigrationVersion determineVersion() {
try {
return MigrationVersion.fromVersion(jdbcMetaData.getDatabaseMajorVersion() + "." + jdbcMetaData.getDatabaseMinorVersion());
} catch (SQLException e) {
throw new FlywaySqlException("Unable to determine the major version of the database", e);
}
}
/**
* Retrieves the script used to create the schema history table.
*
* @param sqlScriptFactory The factory used to create the SQL script.
* @param table The table to create.
* @param baseline Whether to include the creation of a baseline marker.
*/
public final SqlScript getCreateScript(SqlScriptFactory sqlScriptFactory, Table table, boolean baseline) {
return sqlScriptFactory.createSqlScript(new StringResource(getRawCreateScript(table, baseline)), false, null);
}
public abstract String getRawCreateScript(Table table, boolean baseline);
public String getInsertStatement(Table table) {
return "INSERT INTO " + table
+ " (" + quote("installed_rank")
+ ", " + quote("version")
+ ", " + quote("description")
+ ", " + quote("type")
+ ", " + quote("script")
+ ", " + quote("checksum")
+ ", " + quote("installed_by")
+ ", " + quote("execution_time")
+ ", " + quote("success")
+ ")"
+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
}
public final String getBaselineStatement(Table table) {
return String.format(getInsertStatement(table).replace("?", "%s"),
1,
"'" + configuration.getBaselineVersion() + "'",
"'" + AbbreviationUtils.abbreviateDescription(configuration.getBaselineDescription()) + "'",
"'" + MigrationType.BASELINE + "'",
"'" + AbbreviationUtils.abbreviateScript(configuration.getBaselineDescription()) + "'",
"NULL",
"'" + installedBy + "'",
0,
getBooleanTrue()
);
}
public String getSelectStatement(Table table) {
return "SELECT " + quote("installed_rank")
+ "," + quote("version")
+ "," + quote("description")
+ "," + quote("type")
+ "," + quote("script")
+ "," + quote("checksum")
+ "," + quote("installed_on")
+ "," + quote("installed_by")
+ "," + quote("execution_time")
+ "," + quote("success")
+ " FROM " + table
+ " WHERE " + quote("installed_rank") + " > ?"
+ " ORDER BY " + quote("installed_rank");
}
public final String getInstalledBy() {
if (installedBy == null) {
installedBy = configuration.getInstalledBy() == null ? getCurrentUser() : configuration.getInstalledBy();
}
return installedBy;
}
public void close() {
if (!useSingleConnection() && migrationConnection != null) {
migrationConnection.close();
}
if (mainConnection != null) {
mainConnection.close();
}
}
public DatabaseType getDatabaseType() {
return databaseType;
}
public boolean supportsEmptyMigrationDescription() { return true; }
public boolean supportsMultiStatementTransactions() { return true; }
/**
* Cleans all the objects in this database that need to be cleaned before each schema.
*/
public void cleanPreSchemas() {
try {
doCleanPreSchemas();
} catch (SQLException e) {
throw new FlywaySqlException("Unable to clean database " + this, e);
}
}
/**
* Cleans all the objects in this database that need to be cleaned before each schema.
*
* @throws SQLException when the clean failed.
*/
protected void doCleanPreSchemas() throws SQLException { }
/**
* Cleans all the objects in this database that need to be cleaned after each schema.
*
* @param schemas The list of schemas managed by Flyway.
*/
public void cleanPostSchemas(Schema[] schemas) {
try {
doCleanPostSchemas(schemas);
} catch (SQLException e) {
throw new FlywaySqlException("Unable to clean schema " + this, e);
}
}
/**
* Cleans all the objects in this database that need to be cleaned after each schema.
*
* @param schemas The list of schemas managed by Flyway.
* @throws SQLException when the clean failed.
*/
protected void doCleanPostSchemas(Schema[] schemas) throws SQLException { }
public Schema[] getAllSchemas() {
throw new UnsupportedOperationException("Getting all schemas not supported for " + getDatabaseType().getName());
}
}
Schema类
/*
* Copyright (C) Red Gate Software Ltd 2010-2021
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.flywaydb.core.internal.database.base;
import lombok.CustomLog;
import lombok.extern.slf4j.Slf4j;
import org.flywaydb.core.internal.exception.FlywaySqlException;
import org.flywaydb.core.internal.jdbc.JdbcTemplate;
import org.flywaydb.core.internal.jdbc.JdbcUtils;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
@Slf4j
public abstract class Schema<D extends Database, T extends Table> {
protected final JdbcTemplate jdbcTemplate;
protected final D database;
protected final String name;
/**
* @param jdbcTemplate The Jdbc Template for communicating with the DB.
* @param database The database-specific support.
* @param name The name of the schema.
*/
public Schema(JdbcTemplate jdbcTemplate, D database, String name) {
this.jdbcTemplate = jdbcTemplate;
this.database = database;
this.name = name;
}
public String getName() {
return name;
}
public boolean exists() {
try {
return doExists();
} catch (SQLException e) {
throw new FlywaySqlException("Unable to check whether schema " + this + " exists", e);
}
}
/**
* Checks whether this schema exists.
*
* @throws SQLException when the check failed.
*/
protected abstract boolean doExists() throws SQLException;
public boolean empty() {
try {
return doEmpty();
} catch (SQLException e) {
throw new FlywaySqlException("Unable to check whether schema " + this + " is empty", e);
}
}
/**
* Checks whether this schema is empty.
*
* @throws SQLException when the check failed.
*/
protected abstract boolean doEmpty() throws SQLException;
/**
* Creates this schema in the database.
*/
public void create() {
try {
log.info("Creating schema " + this + " ...");
doCreate();
} catch (SQLException e) {
throw new FlywaySqlException("Unable to create schema " + this, e);
}
}
/**
* Creates this schema in the database.
*
* @throws SQLException when the creation failed.
*/
protected abstract void doCreate() throws SQLException;
/**
* Drops this schema from the database.
*/
public void drop() {
try {
doDrop();
} catch (SQLException e) {
throw new FlywaySqlException("Unable to drop schema " + this, e);
}
}
/**
* Drops this schema from the database.
*
* @throws SQLException when the drop failed.
*/
protected abstract void doDrop() throws SQLException;
/**
* Cleans all the objects in this schema.
*/
public void clean() {
try {
doClean();
} catch (SQLException e) {
throw new FlywaySqlException("Unable to clean schema " + this, e);
}
}
/**
* Cleans all the objects in this schema.
*
* @throws SQLException when the clean failed.
*/
protected abstract void doClean() throws SQLException;
/**
* Retrieves all the tables in this schema.
*/
public T[] allTables() {
try {
return doAllTables();
} catch (SQLException e) {
throw new FlywaySqlException("Unable to retrieve all tables in schema " + this, e);
}
}
/**
* Retrieves all the tables in this schema.
*
* @throws SQLException when the retrieval failed.
*/
protected abstract T[] doAllTables() throws SQLException;
/**
* Retrieves all the types in this schema.
*/
protected final Type[] allTypes() {
ResultSet resultSet = null;
try {
resultSet = database.jdbcMetaData.getUDTs(null, name, null, null);
List<Type> types = new ArrayList<>();
while (resultSet.next()) {
types.add(getType(resultSet.getString("TYPE_NAME")));
}
return types.toArray(new Type[0]);
} catch (SQLException e) {
throw new FlywaySqlException("Unable to retrieve all types in schema " + this, e);
} finally {
JdbcUtils.closeResultSet(resultSet);
}
}
/**
* Retrieves the type with this name in this schema.
*/
protected Type getType(String typeName) {
return null;
}
/**
* Retrieves the table with this name in this schema.
*/
public abstract Table getTable(String tableName);
/**
* Retrieves the function with this name in this schema.
*/
public Function getFunction(String functionName, String... args) {
throw new UnsupportedOperationException("getFunction()");
}
/**
* Retrieves all the functions in this schema.
*/
protected final Function[] allFunctions() {
try {
return doAllFunctions();
} catch (SQLException e) {
throw new FlywaySqlException("Unable to retrieve all functions in schema " + this, e);
}
}
/**
* Retrieves all the functions in this schema.
*
* @throws SQLException when the retrieval failed.
*/
protected Function[] doAllFunctions() throws SQLException {
return new Function[0];
}
/**
* @return The quoted name of this schema.
*/
@Override
public String toString() {
return database.quote(name);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Schema schema = (Schema) o;
return name.equals(schema.name);
}
@Override
public int hashCode() {
return name.hashCode();
}
}
三, flyway配置参数
spring.flyway.enabled=true
spring.flyway.url=jdbc:mysql://172.16.1.187:2883/ob_test?userSSL=false&useUnicode=true&characterEncoding=UTF-8&sslMode=DISABLED&serverTimeZone=GMT%2B8
spring.flyway.user=${spring.r2dbc.username}
spring.flyway.driver-class-name=com.mysql.jdbc.Driver
spring.flyway.password=${spring.r2dbc.password}
# ??sql???????????db/migration
spring.flyway.locations=classpath:db/migration
# ??sql????????????V
spring.flyway.sql-migration-prefix=V
# ??sql?????????????2????__
spring.flyway.sql-migration-separator=__
# ??sql?????????
spring.flyway.sql-migration-suffixes=.sql
# ????????????true
spring.flyway.validate-on-migrate=true
# ?????????????????????????????????schema_version?
spring.flyway.baseline-on-migrate=true
四, 在resources目录下创建db.migration目录并在该目录下创建sql文件, V1.0.1__init.sql
CREATE TABLE `QLFieldTest` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`longText` text DEFAULT NULL,
`updateTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`createBy` varchar(100) NOT NULL,
`createTime` datetime DEFAULT NULL
) AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8mb4 ROW_FORMAT = COMPACT COMPRESSION = 'zstd_1.3.8' REPLICA_NUM = 1 BLOCK_SIZE = 16384 USE_BLOOM_FILTER = FALSE TABLET_SIZE = 134217728 PCTFREE = 0;
类似的其他sql文件同理
启动项目后,会生成一张表: flyway_schema_history
参考: