一、Springboot集成flywaydb
- 引入依赖
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
<version>5.0.3</version>
</dependency>
- 创建数据库类
import com.alibaba.druid.pool.DruidDataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
@Configuration
@Primary //在同样的DataSource中,首先使用被标注的DataSource
public class DataSourceConfig {
private Logger log = LoggerFactory.getLogger(DataSourceConfig.class);
@Value("${spring.datasource.url}")
//jdbc:mysql://127.0.0.1:3306/insight?useUnicode=true&characterEncoding=utf8&failOverReadOnly=false&allowMultiQueries=true
private String datasourceUrl;
@Value("${spring.datasource.driver-class-name}")
private String driverClassName;
@Value("${spring.datasource.username}")
private String username;
@Value("${spring.datasource.password}")
private String password;
@Bean //声明其为Bean实例
public DataSource dataSource(){
DruidDataSource datasource = new DruidDataSource();
datasource.setUrl(datasourceUrl);
datasource.setUsername(username);
datasource.setPassword(password);
datasource.setDriverClassName(driverClassName);
try {
Class.forName(driverClassName);
String url01 = datasourceUrl.substring(0,datasourceUrl.indexOf("?"));
String url02 = url01.substring(0,url01.lastIndexOf("/"));
String datasourceName = url01.substring(url01.lastIndexOf("/")+1);
// 连接已经存在的数据库,如:mysql
Connection connection = DriverManager.getConnection(url02, username, password);
Statement statement = connection.createStatement();
// 创建数据库
statement.executeUpdate("create database if not exists `" + datasourceName + "` default character set utf8 COLLATE utf8_general_ci");
statement.close();
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
return datasource;
}
}
3.yml文件配置
flyway:
#是否开启
enabled: true
#迁移脚本的位置,默认db/db
locations: classpath:db/migration
#是否允许无序的迁移
out-of-order: true
#当初始化好连接时要执行的SQL
#init-sqls:
#使用的元数据表名-->版本记录
table: schema_version
# 历史工程接入时,需要设定true
baseline-on-migrate: true
拓展:flyway一些其他配置
flyway.baseline-description对执行迁移时基准版本的描述.
flyway.baseline-on-migrate当迁移时发现目标schema非空,而且带有没有元数据的表时,是否自动执行基准迁移,默认false.
flyway.baseline-version开始执行基准迁移时对现有的schema的版本打标签,默认值为1.
flyway.check-location检查迁移脚本的位置是否存在,默认false.
flyway.clean-on-validation-error当发现校验错误时是否自动调用clean,默认false.
flyway.enabled是否开启flywary,默认true.
flyway.encoding设置迁移时的编码,默认UTF-8.
flyway.ignore-failed-future-migration当读取元数据表时是否忽略错误的迁移,默认false.
flyway.init-sqls当初始化好连接时要执行的SQL.
flyway.locations迁移脚本的位置,默认db/migration.
flyway.out-of-order是否允许无序的迁移,默认false.
flyway.password目标数据库的密码.
flyway.placeholder-prefix设置每个placeholder的前缀,默认${.
flyway.placeholder-replacementplaceholders是否要被替换,默认true.
flyway.placeholder-suffix设置每个placeholder的后缀,默认}.
flyway.placeholders.[placeholder name]设置placeholder的value
flyway.schemas设定需要flywary迁移的schema,大小写敏感,默认为连接默认的schema.
flyway.sql-migration-prefix迁移文件的前缀,默认为V.
flyway.sql-migration-separator迁移脚本的文件名分隔符,默认__
flyway.sql-migration-suffix迁移脚本的后缀,默认为.sql
flyway.tableflyway使用的元数据表名,默认为schema_version
flyway.target迁移时使用的目标版本,默认为latest version
flyway.url迁移时使用的JDBC URL,如果没有指定的话,将使用配置的主数据源
flyway.user迁移数据库的用户名
flyway.validate-on-migrate迁移时是否校验,默认为true.
- 创建sql文件
在classpath下新建/db/migration文件夹,并创建sql脚本文件
sql脚本的格式:V+版本号 +双下划线+时间+结束符
例如:V1__init_table_20190101.sql
USE database #数据库名
DROP TABLE IF EXISTS `config`;
CREATE TABLE `config` (
`ID` int(11) NOT NULL AUTO_INCREMENT COMMENT '配置表',
`TIMEOUT` int(11) DEFAULT NULL COMMENT '超时',
`PING_DELAY` int(11) DEFAULT NULL COMMENT 'PING延迟',
`SEND_TIMES` int(11) DEFAULT NULL COMMENT '发送次数',
`IS_LINK_SETTING` double(11,2) DEFAULT NULL COMMENT '连通性设置',
`HISTORY_RECORD` int(11) DEFAULT NULL COMMENT '历史记录',
`CONCURRENT` int(11) DEFAULT NULL COMMENT '并发度',
PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COMMENT='ping配置表';
二、加载顺序问题
参考文章:使用Spring @DependsOn控制bean加载顺序
问题描述 :程序里把大部分配置都放到数据库里了,也就是说程序启动有些配置要先去查数据库,拿到数据后,再继续配置相关的服务,比如 WebMvcConfigurerAdapter 资源路径配置等初始化工作,这时候就出问题了,flyway还没有执行,数据库里还没有数据,就开始配置其它的一些服务了,到数据库里查不到数据,配置自然就报错了
问题解决思路:自然是控制flyway的执行顺序,让flyway执行在依赖查询数据库配置的服务之前。 问题是springboot集成flyway是自动配置的,也就是说我们要想控制flyway的配置顺序,就得自己重写flyway的配置。
- 重写flyway配置,代码如下:
import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import org.flywaydb.core.Flyway;
import org.flywaydb.core.api.FlywayException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FlywayConfig {
@Autowired
private DataSource dataSource;
private Logger logger = LoggerFactory.getLogger(this.getClass());
@PostConstruct
public void migrate() {
Flyway flyway = new Flyway();
flyway.setDataSource(dataSource);
// 设置flyway扫描sql升级脚本、java升级脚本的目录路径或包路径(表示是src/main/resources/flyway下面,前缀默认为src/main/resources,因为这个路径默认在classpath下面)
flyway.setLocations("db/migration");
// 设置sql脚本文件的编码
flyway.setEncoding("UTF-8");
flyway.setOutOfOrder(true);
try {
flyway.migrate();
} catch (FlywayException e) {
flyway.repair();
logger.error("Flyway配置加载出错",e);
}
}
}
- 将flyway配置从springboot排除,避免springboot自动配置
@SpringBootApplication(exclude = {FlywayAutoConfiguration.class})
@EnableTransactionManagement
public class SiteServerApplication {
public static void main(String[] args) {
SpringApplication.run(SiteServerApplication.class, args);
}
}
- 使用Spring @DependsOn控制bean加载顺序
注意:是在类上添加
@Configuration
@DependsOn("flywayConfig")
public class MyWebMvcConfigurerAdapter extends WebMvcConfigurerAdapte``