当前位置:   article > 正文

flyway实战

flyway实战

flyway是一款用来管理数据库版本的工具框架

一, 添加依赖

  1. <dependency>
  2. <groupId>org.flywaydb</groupId>
  3. <artifactId>flyway-core</artifactId>
  4. </dependency>
  5. <dependency>
  6. <groupId>org.springframework</groupId>
  7. <artifactId>spring-jdbc</artifactId>
  8. </dependency>

二, 编写配置类

MySQLDatabase

  1. /*
  2. * Copyright (C) Red Gate Software Ltd 2010-2021
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.flywaydb.core.internal.database.mysql;
  17. import lombok.CustomLog;
  18. import lombok.extern.slf4j.Slf4j;
  19. import org.flywaydb.core.api.FlywayException;
  20. import org.flywaydb.core.api.MigrationType;
  21. import org.flywaydb.core.api.MigrationVersion;
  22. import org.flywaydb.core.api.configuration.Configuration;
  23. import org.flywaydb.core.internal.database.base.Database;
  24. import org.flywaydb.core.internal.database.base.BaseDatabaseType;
  25. import org.flywaydb.core.internal.database.base.Table;
  26. import org.flywaydb.core.internal.database.mysql.mariadb.MariaDBDatabaseType;
  27. import org.flywaydb.core.internal.jdbc.JdbcConnectionFactory;
  28. import org.flywaydb.core.internal.jdbc.JdbcTemplate;
  29. import org.flywaydb.core.internal.jdbc.StatementInterceptor;
  30. import java.sql.Connection;
  31. import java.sql.SQLException;
  32. import java.util.regex.Matcher;
  33. import java.util.regex.Pattern;
  34. @Slf4j
  35. public class MySQLDatabase extends Database<MySQLConnection> {
  36. // See https://mariadb.com/kb/en/version/
  37. private static final Pattern MARIADB_VERSION_PATTERN = Pattern.compile("(\\d+\\.\\d+)\\.\\d+(-\\d+)*-MariaDB(-\\w+)*");
  38. private static final Pattern MARIADB_WITH_MAXSCALE_VERSION_PATTERN = Pattern.compile("(\\d+\\.\\d+)\\.\\d+(-\\d+)* (\\d+\\.\\d+)\\.\\d+(-\\d+)*-maxscale(-\\w+)*");
  39. private static final Pattern MYSQL_VERSION_PATTERN = Pattern.compile("(\\d+\\.\\d+)\\.\\d+\\w*");
  40. /**
  41. * Whether this is a Percona XtraDB Cluster in strict mode.
  42. */
  43. private final boolean pxcStrict;
  44. /**
  45. * Whether this database is enforcing GTID consistency.
  46. */
  47. private final boolean gtidConsistencyEnforced;
  48. /**
  49. * Whether the event scheduler table is queryable.
  50. */
  51. final boolean eventSchedulerQueryable;
  52. public MySQLDatabase(Configuration configuration, JdbcConnectionFactory jdbcConnectionFactory, StatementInterceptor statementInterceptor) {
  53. super(configuration, jdbcConnectionFactory, statementInterceptor);
  54. JdbcTemplate jdbcTemplate = new JdbcTemplate(rawMainJdbcConnection, databaseType);
  55. pxcStrict = isMySQL() && isRunningInPerconaXtraDBClusterWithStrictMode(jdbcTemplate);
  56. gtidConsistencyEnforced = isMySQL() && isRunningInGTIDConsistencyMode(jdbcTemplate);
  57. eventSchedulerQueryable = false;
  58. }
  59. private static boolean isEventSchedulerQueryable(JdbcTemplate jdbcTemplate) {
  60. try {
  61. // Attempt query
  62. jdbcTemplate.queryForString("SELECT event_name FROM information_schema.events LIMIT 1");
  63. return true;
  64. } catch (SQLException e) {
  65. log.debug("Detected unqueryable MariaDB event scheduler, most likely due to it being OFF or DISABLED.");
  66. return false;
  67. }
  68. }
  69. static boolean isRunningInPerconaXtraDBClusterWithStrictMode(JdbcTemplate jdbcTemplate) {
  70. try {
  71. String pcx_strict_mode = jdbcTemplate.queryForString(
  72. "select VARIABLE_VALUE from performance_schema.global_variables"
  73. + " where variable_name = 'pxc_strict_mode'");
  74. if ("ENFORCING".equals(pcx_strict_mode) || "MASTER".equals(pcx_strict_mode)) {
  75. log.debug("Detected Percona XtraDB Cluster in strict mode");
  76. return true;
  77. }
  78. } catch (SQLException e) {
  79. log.debug("Unable to detect whether we are running in a Percona XtraDB Cluster. Assuming not to be.");
  80. }
  81. return false;
  82. }
  83. static boolean isRunningInGTIDConsistencyMode(JdbcTemplate jdbcTemplate) {
  84. try {
  85. String gtidConsistency = jdbcTemplate.queryForString("SELECT @@GLOBAL.ENFORCE_GTID_CONSISTENCY");
  86. if ("ON".equals(gtidConsistency)) {
  87. log.debug("Detected GTID consistency being enforced");
  88. return true;
  89. }
  90. } catch (SQLException e) {
  91. log.debug("Unable to detect whether database enforces GTID consistency. Assuming not.");
  92. }
  93. return false;
  94. }
  95. boolean isMySQL() {
  96. return databaseType instanceof MySQLDatabaseType;
  97. }
  98. boolean isMariaDB() {
  99. return databaseType instanceof MariaDBDatabaseType;
  100. }
  101. boolean isPxcStrict() {
  102. return pxcStrict;
  103. }
  104. /*
  105. * CREATE TABLE ... AS SELECT ... cannot be used in three scenarios:
  106. * - Percona XtraDB Cluster in strict mode doesn't support it
  107. * - TiDB doesn't support it (overridden elsewhere)
  108. * - When GTID consistency is being enforced. Note that if GTID_MODE is ON, then ENFORCE_GTID_CONSISTENCY is
  109. * necessarily ON as well.
  110. */
  111. protected boolean isCreateTableAsSelectAllowed() {
  112. return !pxcStrict && !gtidConsistencyEnforced;
  113. }
  114. @Override
  115. public String getRawCreateScript(Table table, boolean baseline) {
  116. String tablespace =
  117. configuration.getTablespace() == null
  118. ? ""
  119. : " TABLESPACE \"" + configuration.getTablespace() + "\"";
  120. String baselineMarker = "";
  121. if (baseline) {
  122. if (isCreateTableAsSelectAllowed()) {
  123. baselineMarker = " AS SELECT" +
  124. " 1 as \"installed_rank\"," +
  125. " '" + configuration.getBaselineVersion() + "' as \"version\"," +
  126. " '" + configuration.getBaselineDescription() + "' as \"description\"," +
  127. " '" + MigrationType.BASELINE + "' as \"type\"," +
  128. " '" + configuration.getBaselineDescription() + "' as \"script\"," +
  129. " NULL as \"checksum\"," +
  130. " '" + getInstalledBy() + "' as \"installed_by\"," +
  131. " CURRENT_TIMESTAMP as \"installed_on\"," +
  132. " 0 as \"execution_time\"," +
  133. " TRUE as \"success\"\n";
  134. } else {
  135. // Revert to regular insert, which unfortunately is not safe in concurrent scenarios
  136. // due to MySQL implicit commits after DDL statements.
  137. baselineMarker = ";\n" + getBaselineStatement(table);
  138. }
  139. }
  140. return "CREATE TABLE " + table + " (\n" +
  141. " `installed_rank` INT NOT NULL,\n" +
  142. " `version` VARCHAR(50),\n" +
  143. " `description` VARCHAR(200) NOT NULL,\n" +
  144. " `type` VARCHAR(20) NOT NULL,\n" +
  145. " `script` VARCHAR(1000) NOT NULL,\n" +
  146. " `checksum` INT,\n" +
  147. " `installed_by` VARCHAR(100) NOT NULL,\n" +
  148. " `installed_on` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\n" +
  149. " `execution_time` INT NOT NULL,\n" +
  150. " `success` BOOL NOT NULL,\n" +
  151. " CONSTRAINT " + getConstraintName(table.getName()) + " PRIMARY KEY (`installed_rank`)\n" +
  152. ")" + tablespace + " ENGINE=InnoDB" +
  153. baselineMarker +
  154. ";\n" +
  155. "CREATE INDEX `" + table.getName() + "_s_idx` ON " + table + " (`success`);";
  156. }
  157. protected String getConstraintName(String tableName) {
  158. return "`" + tableName + "_pk`";
  159. }
  160. @Override
  161. protected MySQLConnection doGetConnection(Connection connection) {
  162. return new MySQLConnection(this, connection);
  163. }
  164. @Override
  165. protected MigrationVersion determineVersion() {
  166. // Ignore the version from the JDBC metadata and use the version returned by the database since proxies such as
  167. // Azure or ProxySQL return incorrect versions
  168. String selectVersionOutput = BaseDatabaseType.getSelectVersionOutput(rawMainJdbcConnection);
  169. if (databaseType instanceof MariaDBDatabaseType) {
  170. return extractMariaDBVersionFromString(selectVersionOutput);
  171. }
  172. return extractMySQLVersionFromString(selectVersionOutput);
  173. }
  174. static MigrationVersion extractMySQLVersionFromString(String selectVersionOutput) {
  175. return extractVersionFromString(selectVersionOutput, MYSQL_VERSION_PATTERN);
  176. }
  177. static MigrationVersion extractMariaDBVersionFromString(String selectVersionOutput) {
  178. return extractVersionFromString(selectVersionOutput, MARIADB_VERSION_PATTERN, MARIADB_WITH_MAXSCALE_VERSION_PATTERN);
  179. }
  180. /*
  181. * Given a version string that may contain unwanted text, extract out the version part.
  182. */
  183. private static MigrationVersion extractVersionFromString(String versionString, Pattern... patterns) {
  184. for (Pattern pattern : patterns) {
  185. Matcher matcher = pattern.matcher(versionString);
  186. if (matcher.find()) {
  187. return MigrationVersion.fromVersion(matcher.group(1));
  188. }
  189. }
  190. throw new FlywayException("Unable to determine version from '" + versionString + "'");
  191. }
  192. @Override
  193. public final void ensureSupported() {
  194. ensureDatabaseIsRecentEnough("5.1");
  195. if (databaseType instanceof MariaDBDatabaseType) {
  196. ensureDatabaseNotOlderThanOtherwiseRecommendUpgradeToFlywayEdition("10.3", org.flywaydb.core.internal.license.Edition.ENTERPRISE);
  197. recommendFlywayUpgradeIfNecessary("10.6");
  198. } else {
  199. ensureDatabaseNotOlderThanOtherwiseRecommendUpgradeToFlywayEdition("8.0", org.flywaydb.core.internal.license.Edition.ENTERPRISE);
  200. recommendFlywayUpgradeIfNecessary("8.0");
  201. }
  202. }
  203. @Override
  204. protected String doGetCurrentUser() throws SQLException {
  205. return getMainConnection().getJdbcTemplate().queryForString("SELECT SUBSTRING_INDEX(USER(),'@',1)");
  206. }
  207. @Override
  208. public boolean supportsDdlTransactions() {
  209. return false;
  210. }
  211. @Override
  212. public boolean supportsChangingCurrentSchema() {
  213. return true;
  214. }
  215. @Override
  216. public String getBooleanTrue() {
  217. return "1";
  218. }
  219. @Override
  220. public String getBooleanFalse() {
  221. return "0";
  222. }
  223. @Override
  224. public String doQuote(String identifier) {
  225. return "`" + identifier + "`";
  226. }
  227. @Override
  228. public boolean catalogIsSchema() {
  229. return true;
  230. }
  231. @Override
  232. public boolean useSingleConnection() {
  233. return !pxcStrict;
  234. }
  235. }

MySQLNamedLockTemplate

  1. /*
  2. * Copyright (C) Red Gate Software Ltd 2010-2021
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.flywaydb.core.internal.database.mysql;
  17. import java.sql.SQLException;
  18. import java.util.concurrent.Callable;
  19. import lombok.extern.slf4j.Slf4j;
  20. import org.flywaydb.core.api.FlywayException;
  21. import org.flywaydb.core.internal.exception.FlywaySqlException;
  22. import org.flywaydb.core.internal.jdbc.JdbcTemplate;
  23. /**
  24. * Spring-like template for executing with MySQL named locks.
  25. */
  26. @Slf4j
  27. public class MySQLNamedLockTemplate {
  28. /**
  29. * The connection for the named lock.
  30. */
  31. private final JdbcTemplate jdbcTemplate;
  32. private final String lockName;
  33. /**
  34. * Creates a new named lock template for this connection.
  35. *
  36. * @param jdbcTemplate The jdbcTemplate for the connection.
  37. * @param discriminator A number to discriminate between locks.
  38. */
  39. MySQLNamedLockTemplate(JdbcTemplate jdbcTemplate, int discriminator) {
  40. this.jdbcTemplate = jdbcTemplate;
  41. lockName = "Flyway-" + discriminator;
  42. }
  43. /**
  44. * Executes this callback with a named lock.
  45. *
  46. * @param callable The callback to execute.
  47. * @return The result of the callable code.
  48. */
  49. public <T> T execute(Callable<T> callable) {
  50. try {
  51. lock();
  52. return callable.call();
  53. } catch (SQLException e) {
  54. throw new FlywaySqlException("Unable to acquire MySQL named lock: " + lockName, e);
  55. } catch (Exception e) {
  56. RuntimeException rethrow;
  57. if (e instanceof RuntimeException) {
  58. rethrow = (RuntimeException) e;
  59. } else {
  60. rethrow = new FlywayException(e);
  61. }
  62. throw rethrow;
  63. } finally {
  64. try {
  65. //FIXME ocean base 没有GET_LOCK 需要通过其他方式来实现flyway锁
  66. if (1 == 1) {
  67. } else {
  68. jdbcTemplate.execute("SELECT RELEASE_LOCK('" + lockName + "')");
  69. }
  70. } catch (SQLException e) {
  71. log.error("Unable to release MySQL named lock: " + lockName, e);
  72. }
  73. }
  74. }
  75. private void lock() throws SQLException {
  76. while (!tryLock()) {
  77. try {
  78. Thread.sleep(100L);
  79. } catch (InterruptedException e) {
  80. throw new FlywayException(
  81. "Interrupted while attempting to acquire MySQL named lock: " + lockName, e);
  82. }
  83. }
  84. }
  85. private boolean tryLock() throws SQLException {
  86. //FIXME ocean base 没有GET_LOCK 需要通过其他方式来实现flyway锁
  87. if (1 == 1) {
  88. return true;
  89. }
  90. return jdbcTemplate.queryForInt("SELECT GET_LOCK(?,10)", lockName) == 1;
  91. }
  92. }

Databse类

  1. /*
  2. * Copyright (C) Red Gate Software Ltd 2010-2021
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.flywaydb.core.internal.database.base;
  17. import lombok.CustomLog;
  18. import lombok.extern.slf4j.Slf4j;
  19. import org.flywaydb.core.api.MigrationType;
  20. import org.flywaydb.core.api.MigrationVersion;
  21. import org.flywaydb.core.api.configuration.Configuration;
  22. import org.flywaydb.core.internal.database.DatabaseType;
  23. import org.flywaydb.core.internal.exception.FlywayDbUpgradeRequiredException;
  24. import org.flywaydb.core.internal.exception.FlywaySqlException;
  25. import org.flywaydb.core.internal.jdbc.JdbcConnectionFactory;
  26. import org.flywaydb.core.internal.jdbc.JdbcTemplate;
  27. import org.flywaydb.core.internal.jdbc.StatementInterceptor;
  28. import org.flywaydb.core.internal.license.Edition;
  29. import org.flywaydb.core.internal.license.FlywayEditionUpgradeRequiredException;
  30. import org.flywaydb.core.internal.resource.StringResource;
  31. import org.flywaydb.core.internal.sqlscript.Delimiter;
  32. import org.flywaydb.core.internal.sqlscript.SqlScript;
  33. import org.flywaydb.core.internal.sqlscript.SqlScriptFactory;
  34. import org.flywaydb.core.internal.util.AbbreviationUtils;
  35. import java.io.Closeable;
  36. import java.sql.DatabaseMetaData;
  37. import java.sql.SQLException;
  38. /**
  39. * Abstraction for database-specific functionality.
  40. */
  41. @Slf4j
  42. public abstract class Database<C extends Connection> implements Closeable {
  43. protected final DatabaseType databaseType;
  44. protected final Configuration configuration;
  45. protected final StatementInterceptor statementInterceptor;
  46. protected final JdbcConnectionFactory jdbcConnectionFactory;
  47. protected final DatabaseMetaData jdbcMetaData;
  48. protected JdbcTemplate jdbcTemplate;
  49. private C migrationConnection;
  50. private C mainConnection;
  51. /**
  52. * The main JDBC connection, without any wrapping.
  53. */
  54. protected final java.sql.Connection rawMainJdbcConnection;
  55. /**
  56. * The 'major.minor' version of this database.
  57. */
  58. private MigrationVersion version;
  59. /**
  60. * The user who applied the migrations.
  61. */
  62. private String installedBy;
  63. public Database(Configuration configuration, JdbcConnectionFactory jdbcConnectionFactory, StatementInterceptor statementInterceptor) {
  64. this.databaseType = jdbcConnectionFactory.getDatabaseType();
  65. this.configuration = configuration;
  66. this.rawMainJdbcConnection = jdbcConnectionFactory.openConnection();
  67. try {
  68. this.jdbcMetaData = rawMainJdbcConnection.getMetaData();
  69. } catch (SQLException e) {
  70. throw new FlywaySqlException("Unable to get metadata for connection", e);
  71. }
  72. this.jdbcTemplate = new JdbcTemplate(rawMainJdbcConnection, databaseType);
  73. this.jdbcConnectionFactory = jdbcConnectionFactory;
  74. this.statementInterceptor = statementInterceptor;
  75. }
  76. /**
  77. * Retrieves a Flyway Connection for this JDBC connection.
  78. */
  79. private C getConnection(java.sql.Connection connection) {
  80. return doGetConnection(connection);
  81. }
  82. /**
  83. * Retrieves a Flyway Connection for this JDBC connection.
  84. */
  85. protected abstract C doGetConnection(java.sql.Connection connection);
  86. /**
  87. * Ensure Flyway supports this version of this database.
  88. */
  89. public abstract void ensureSupported();
  90. /**
  91. * @return The 'major.minor' version of this database.
  92. */
  93. public final MigrationVersion getVersion() {
  94. if (version == null) {
  95. version = determineVersion();
  96. }
  97. return version;
  98. }
  99. protected final void ensureDatabaseIsRecentEnough(String oldestSupportedVersion) {
  100. /* if (!getVersion().isAtLeast(oldestSupportedVersion)) {
  101. throw new FlywayDbUpgradeRequiredException(
  102. databaseType,
  103. computeVersionDisplayName(getVersion()),
  104. computeVersionDisplayName(MigrationVersion.fromVersion(oldestSupportedVersion)));
  105. }*/
  106. }
  107. /**
  108. * Ensure this database it at least as recent as this version otherwise suggest upgrade to this higher edition of
  109. * Flyway.
  110. */
  111. protected final void ensureDatabaseNotOlderThanOtherwiseRecommendUpgradeToFlywayEdition(String oldestSupportedVersionInThisEdition,
  112. Edition editionWhereStillSupported) {
  113. /* if (!getVersion().isAtLeast(oldestSupportedVersionInThisEdition)) {
  114. throw new FlywayEditionUpgradeRequiredException(
  115. editionWhereStillSupported,
  116. databaseType,
  117. computeVersionDisplayName(getVersion()));
  118. }*/
  119. }
  120. protected final void recommendFlywayUpgradeIfNecessary(String newestSupportedVersion) {
  121. if (getVersion().isNewerThan(newestSupportedVersion)) {
  122. recommendFlywayUpgrade(newestSupportedVersion);
  123. }
  124. }
  125. protected final void recommendFlywayUpgradeIfNecessaryForMajorVersion(String newestSupportedVersion) {
  126. if (getVersion().isMajorNewerThan(newestSupportedVersion)) {
  127. recommendFlywayUpgrade(newestSupportedVersion);
  128. }
  129. }
  130. protected final void notifyDatabaseIsNotFormallySupported() {
  131. String message = "Support for " + databaseType + " is provided only on a community-led basis, and is not formally supported by Redgate";
  132. log.warn(message);
  133. }
  134. private void recommendFlywayUpgrade(String newestSupportedVersion) {
  135. String message = "Flyway upgrade recommended: " + databaseType + " " + computeVersionDisplayName(getVersion())
  136. + " is newer than this version of Flyway and support has not been tested."
  137. + " The latest supported version of " + databaseType + " is " + newestSupportedVersion + ".";
  138. log.warn(message);
  139. }
  140. /**
  141. * Compute the user-friendly display name for this database version.
  142. */
  143. protected String computeVersionDisplayName(MigrationVersion version) {
  144. return version.getVersion();
  145. }
  146. public Delimiter getDefaultDelimiter() {
  147. return Delimiter.SEMICOLON;
  148. }
  149. /**
  150. * @return The name of the database, by default as determined by JDBC.
  151. */
  152. public final String getCatalog() {
  153. try {
  154. return doGetCatalog();
  155. } catch (SQLException e) {
  156. throw new FlywaySqlException("Error retrieving the database name", e);
  157. }
  158. }
  159. protected String doGetCatalog() throws SQLException {
  160. return getMainConnection().getJdbcConnection().getCatalog();
  161. }
  162. public final String getCurrentUser() {
  163. try {
  164. return doGetCurrentUser();
  165. } catch (SQLException e) {
  166. throw new FlywaySqlException("Error retrieving the database user", e);
  167. }
  168. }
  169. protected String doGetCurrentUser() throws SQLException {
  170. return jdbcMetaData.getUserName();
  171. }
  172. public abstract boolean supportsDdlTransactions();
  173. public abstract boolean supportsChangingCurrentSchema();
  174. /**
  175. * @return The representation of the value {@code true} in a boolean column.
  176. */
  177. public abstract String getBooleanTrue();
  178. /**
  179. * @return The representation of the value {@code false} in a boolean column.
  180. */
  181. public abstract String getBooleanFalse();
  182. /**
  183. * Quotes these identifiers for use in SQL queries. Multiple identifiers will be quoted and separated by a dot.
  184. */
  185. public final String quote(String... identifiers) {
  186. StringBuilder result = new StringBuilder();
  187. boolean first = true;
  188. for (String identifier : identifiers) {
  189. if (!first) {
  190. result.append(".");
  191. }
  192. first = false;
  193. result.append(doQuote(identifier));
  194. }
  195. return result.toString();
  196. }
  197. /**
  198. * Quotes this identifier for use in SQL queries.
  199. */
  200. protected abstract String doQuote(String identifier);
  201. /**
  202. * @return {@code true} if this database uses a catalog to represent a schema, or {@code false} if a schema is
  203. * simply a schema.
  204. */
  205. public abstract boolean catalogIsSchema();
  206. /**
  207. * @return Whether to use a single connection for both schema history table management and applying migrations.
  208. */
  209. public boolean useSingleConnection() {
  210. return false;
  211. }
  212. public DatabaseMetaData getJdbcMetaData() {
  213. return jdbcMetaData;
  214. }
  215. /**
  216. * @return The main connection used to manipulate the schema history.
  217. */
  218. public final C getMainConnection() {
  219. if (mainConnection == null) {
  220. this.mainConnection = getConnection(rawMainJdbcConnection);
  221. }
  222. return mainConnection;
  223. }
  224. /**
  225. * @return The migration connection used to apply migrations.
  226. */
  227. public final C getMigrationConnection() {
  228. if (migrationConnection == null) {
  229. if (useSingleConnection()) {
  230. this.migrationConnection = getMainConnection();
  231. } else {
  232. this.migrationConnection = getConnection(jdbcConnectionFactory.openConnection());
  233. }
  234. }
  235. return migrationConnection;
  236. }
  237. /**
  238. * @return The major and minor version of the database.
  239. */
  240. protected MigrationVersion determineVersion() {
  241. try {
  242. return MigrationVersion.fromVersion(jdbcMetaData.getDatabaseMajorVersion() + "." + jdbcMetaData.getDatabaseMinorVersion());
  243. } catch (SQLException e) {
  244. throw new FlywaySqlException("Unable to determine the major version of the database", e);
  245. }
  246. }
  247. /**
  248. * Retrieves the script used to create the schema history table.
  249. *
  250. * @param sqlScriptFactory The factory used to create the SQL script.
  251. * @param table The table to create.
  252. * @param baseline Whether to include the creation of a baseline marker.
  253. */
  254. public final SqlScript getCreateScript(SqlScriptFactory sqlScriptFactory, Table table, boolean baseline) {
  255. return sqlScriptFactory.createSqlScript(new StringResource(getRawCreateScript(table, baseline)), false, null);
  256. }
  257. public abstract String getRawCreateScript(Table table, boolean baseline);
  258. public String getInsertStatement(Table table) {
  259. return "INSERT INTO " + table
  260. + " (" + quote("installed_rank")
  261. + ", " + quote("version")
  262. + ", " + quote("description")
  263. + ", " + quote("type")
  264. + ", " + quote("script")
  265. + ", " + quote("checksum")
  266. + ", " + quote("installed_by")
  267. + ", " + quote("execution_time")
  268. + ", " + quote("success")
  269. + ")"
  270. + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
  271. }
  272. public final String getBaselineStatement(Table table) {
  273. return String.format(getInsertStatement(table).replace("?", "%s"),
  274. 1,
  275. "'" + configuration.getBaselineVersion() + "'",
  276. "'" + AbbreviationUtils.abbreviateDescription(configuration.getBaselineDescription()) + "'",
  277. "'" + MigrationType.BASELINE + "'",
  278. "'" + AbbreviationUtils.abbreviateScript(configuration.getBaselineDescription()) + "'",
  279. "NULL",
  280. "'" + installedBy + "'",
  281. 0,
  282. getBooleanTrue()
  283. );
  284. }
  285. public String getSelectStatement(Table table) {
  286. return "SELECT " + quote("installed_rank")
  287. + "," + quote("version")
  288. + "," + quote("description")
  289. + "," + quote("type")
  290. + "," + quote("script")
  291. + "," + quote("checksum")
  292. + "," + quote("installed_on")
  293. + "," + quote("installed_by")
  294. + "," + quote("execution_time")
  295. + "," + quote("success")
  296. + " FROM " + table
  297. + " WHERE " + quote("installed_rank") + " > ?"
  298. + " ORDER BY " + quote("installed_rank");
  299. }
  300. public final String getInstalledBy() {
  301. if (installedBy == null) {
  302. installedBy = configuration.getInstalledBy() == null ? getCurrentUser() : configuration.getInstalledBy();
  303. }
  304. return installedBy;
  305. }
  306. public void close() {
  307. if (!useSingleConnection() && migrationConnection != null) {
  308. migrationConnection.close();
  309. }
  310. if (mainConnection != null) {
  311. mainConnection.close();
  312. }
  313. }
  314. public DatabaseType getDatabaseType() {
  315. return databaseType;
  316. }
  317. public boolean supportsEmptyMigrationDescription() { return true; }
  318. public boolean supportsMultiStatementTransactions() { return true; }
  319. /**
  320. * Cleans all the objects in this database that need to be cleaned before each schema.
  321. */
  322. public void cleanPreSchemas() {
  323. try {
  324. doCleanPreSchemas();
  325. } catch (SQLException e) {
  326. throw new FlywaySqlException("Unable to clean database " + this, e);
  327. }
  328. }
  329. /**
  330. * Cleans all the objects in this database that need to be cleaned before each schema.
  331. *
  332. * @throws SQLException when the clean failed.
  333. */
  334. protected void doCleanPreSchemas() throws SQLException { }
  335. /**
  336. * Cleans all the objects in this database that need to be cleaned after each schema.
  337. *
  338. * @param schemas The list of schemas managed by Flyway.
  339. */
  340. public void cleanPostSchemas(Schema[] schemas) {
  341. try {
  342. doCleanPostSchemas(schemas);
  343. } catch (SQLException e) {
  344. throw new FlywaySqlException("Unable to clean schema " + this, e);
  345. }
  346. }
  347. /**
  348. * Cleans all the objects in this database that need to be cleaned after each schema.
  349. *
  350. * @param schemas The list of schemas managed by Flyway.
  351. * @throws SQLException when the clean failed.
  352. */
  353. protected void doCleanPostSchemas(Schema[] schemas) throws SQLException { }
  354. public Schema[] getAllSchemas() {
  355. throw new UnsupportedOperationException("Getting all schemas not supported for " + getDatabaseType().getName());
  356. }
  357. }

Schema类

  1. /*
  2. * Copyright (C) Red Gate Software Ltd 2010-2021
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.flywaydb.core.internal.database.base;
  17. import lombok.CustomLog;
  18. import lombok.extern.slf4j.Slf4j;
  19. import org.flywaydb.core.internal.exception.FlywaySqlException;
  20. import org.flywaydb.core.internal.jdbc.JdbcTemplate;
  21. import org.flywaydb.core.internal.jdbc.JdbcUtils;
  22. import java.sql.ResultSet;
  23. import java.sql.SQLException;
  24. import java.util.ArrayList;
  25. import java.util.List;
  26. @Slf4j
  27. public abstract class Schema<D extends Database, T extends Table> {
  28. protected final JdbcTemplate jdbcTemplate;
  29. protected final D database;
  30. protected final String name;
  31. /**
  32. * @param jdbcTemplate The Jdbc Template for communicating with the DB.
  33. * @param database The database-specific support.
  34. * @param name The name of the schema.
  35. */
  36. public Schema(JdbcTemplate jdbcTemplate, D database, String name) {
  37. this.jdbcTemplate = jdbcTemplate;
  38. this.database = database;
  39. this.name = name;
  40. }
  41. public String getName() {
  42. return name;
  43. }
  44. public boolean exists() {
  45. try {
  46. return doExists();
  47. } catch (SQLException e) {
  48. throw new FlywaySqlException("Unable to check whether schema " + this + " exists", e);
  49. }
  50. }
  51. /**
  52. * Checks whether this schema exists.
  53. *
  54. * @throws SQLException when the check failed.
  55. */
  56. protected abstract boolean doExists() throws SQLException;
  57. public boolean empty() {
  58. try {
  59. return doEmpty();
  60. } catch (SQLException e) {
  61. throw new FlywaySqlException("Unable to check whether schema " + this + " is empty", e);
  62. }
  63. }
  64. /**
  65. * Checks whether this schema is empty.
  66. *
  67. * @throws SQLException when the check failed.
  68. */
  69. protected abstract boolean doEmpty() throws SQLException;
  70. /**
  71. * Creates this schema in the database.
  72. */
  73. public void create() {
  74. try {
  75. log.info("Creating schema " + this + " ...");
  76. doCreate();
  77. } catch (SQLException e) {
  78. throw new FlywaySqlException("Unable to create schema " + this, e);
  79. }
  80. }
  81. /**
  82. * Creates this schema in the database.
  83. *
  84. * @throws SQLException when the creation failed.
  85. */
  86. protected abstract void doCreate() throws SQLException;
  87. /**
  88. * Drops this schema from the database.
  89. */
  90. public void drop() {
  91. try {
  92. doDrop();
  93. } catch (SQLException e) {
  94. throw new FlywaySqlException("Unable to drop schema " + this, e);
  95. }
  96. }
  97. /**
  98. * Drops this schema from the database.
  99. *
  100. * @throws SQLException when the drop failed.
  101. */
  102. protected abstract void doDrop() throws SQLException;
  103. /**
  104. * Cleans all the objects in this schema.
  105. */
  106. public void clean() {
  107. try {
  108. doClean();
  109. } catch (SQLException e) {
  110. throw new FlywaySqlException("Unable to clean schema " + this, e);
  111. }
  112. }
  113. /**
  114. * Cleans all the objects in this schema.
  115. *
  116. * @throws SQLException when the clean failed.
  117. */
  118. protected abstract void doClean() throws SQLException;
  119. /**
  120. * Retrieves all the tables in this schema.
  121. */
  122. public T[] allTables() {
  123. try {
  124. return doAllTables();
  125. } catch (SQLException e) {
  126. throw new FlywaySqlException("Unable to retrieve all tables in schema " + this, e);
  127. }
  128. }
  129. /**
  130. * Retrieves all the tables in this schema.
  131. *
  132. * @throws SQLException when the retrieval failed.
  133. */
  134. protected abstract T[] doAllTables() throws SQLException;
  135. /**
  136. * Retrieves all the types in this schema.
  137. */
  138. protected final Type[] allTypes() {
  139. ResultSet resultSet = null;
  140. try {
  141. resultSet = database.jdbcMetaData.getUDTs(null, name, null, null);
  142. List<Type> types = new ArrayList<>();
  143. while (resultSet.next()) {
  144. types.add(getType(resultSet.getString("TYPE_NAME")));
  145. }
  146. return types.toArray(new Type[0]);
  147. } catch (SQLException e) {
  148. throw new FlywaySqlException("Unable to retrieve all types in schema " + this, e);
  149. } finally {
  150. JdbcUtils.closeResultSet(resultSet);
  151. }
  152. }
  153. /**
  154. * Retrieves the type with this name in this schema.
  155. */
  156. protected Type getType(String typeName) {
  157. return null;
  158. }
  159. /**
  160. * Retrieves the table with this name in this schema.
  161. */
  162. public abstract Table getTable(String tableName);
  163. /**
  164. * Retrieves the function with this name in this schema.
  165. */
  166. public Function getFunction(String functionName, String... args) {
  167. throw new UnsupportedOperationException("getFunction()");
  168. }
  169. /**
  170. * Retrieves all the functions in this schema.
  171. */
  172. protected final Function[] allFunctions() {
  173. try {
  174. return doAllFunctions();
  175. } catch (SQLException e) {
  176. throw new FlywaySqlException("Unable to retrieve all functions in schema " + this, e);
  177. }
  178. }
  179. /**
  180. * Retrieves all the functions in this schema.
  181. *
  182. * @throws SQLException when the retrieval failed.
  183. */
  184. protected Function[] doAllFunctions() throws SQLException {
  185. return new Function[0];
  186. }
  187. /**
  188. * @return The quoted name of this schema.
  189. */
  190. @Override
  191. public String toString() {
  192. return database.quote(name);
  193. }
  194. @Override
  195. public boolean equals(Object o) {
  196. if (this == o) return true;
  197. if (o == null || getClass() != o.getClass()) return false;
  198. Schema schema = (Schema) o;
  199. return name.equals(schema.name);
  200. }
  201. @Override
  202. public int hashCode() {
  203. return name.hashCode();
  204. }
  205. }

三, flyway配置参数

  1. spring.flyway.enabled=true
  2. spring.flyway.url=jdbc:mysql://172.16.1.187:2883/ob_test?userSSL=false&useUnicode=true&characterEncoding=UTF-8&sslMode=DISABLED&serverTimeZone=GMT%2B8
  3. spring.flyway.user=${spring.r2dbc.username}
  4. spring.flyway.driver-class-name=com.mysql.jdbc.Driver
  5. spring.flyway.password=${spring.r2dbc.password}
  6. # ??sql???????????db/migration
  7. spring.flyway.locations=classpath:db/migration
  8. # ??sql????????????V
  9. spring.flyway.sql-migration-prefix=V
  10. # ??sql?????????????2????__
  11. spring.flyway.sql-migration-separator=__
  12. # ??sql?????????
  13. spring.flyway.sql-migration-suffixes=.sql
  14. # ????????????true
  15. spring.flyway.validate-on-migrate=true
  16. # ?????????????????????????????????schema_version?
  17. spring.flyway.baseline-on-migrate=true

四, 在resources目录下创建db.migration目录并在该目录下创建sql文件, V1.0.1__init.sql

  1. CREATE TABLE `QLFieldTest` (
  2. `id` bigint(20) NOT NULL AUTO_INCREMENT,
  3. `longText` text DEFAULT NULL,
  4. `updateTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  5. `createBy` varchar(100) NOT NULL,
  6. `createTime` datetime DEFAULT NULL
  7. ) 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

参考:

Flyway快速上手教程 - 简书

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/202747
推荐阅读
相关标签
  

闽ICP备14008679号