引言
Hello,大家好,这里是Anyin。
在我们日常的后端Java开发工作当中,不可避免的与SQL脚本打交道。每个公司对于SQL脚本的管理方式可能都不太相同,但是都会有一个共同的痛点:遗漏SQL脚本。
我们在日常的开发过程中,一般都是多人协作并且是多环境切换,例如:开发、测试、演示、生产等环境,基本开发流程是开发人员在开发环境开发功能完成之后,代码合并到测试环境并部署,测试人员测试完成之后代码合并到演示环境并部署,最后在演示环境验收完成之后,代码接着合并到生产环境并部署。
在这个过程中,可能会涉及大量的SQL脚本,并且在环境切换的时候出现遗漏,例如:在演示环境出现一个问题,那么开发可能写一个SQL脚本,然后在演示环境执行了,因为流程是往下走的,最后会造成演示环境和生产环境表结构正确,开发和测试缺异常。
基于以上问题,今天我们来看看怎么使用Flyway管理SQL脚本从而解决脚本遗漏的问题。
方法一:使用插件方式
Flyway提供了基于Maven的插件方式。配置如下:
<plugin>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-maven-plugin</artifactId>
<version>4.1.0</version>
<configuration>
<user>${db.user}</user>
<password>${db.password}</password>
<driver>com.mysql.jdbc.Driver</driver>
<url>${jdbc.url}</url>
<locations>
<location>db/migration</location>
</locations>
<table>schema_version</table>
<cleanDisabled>true</cleanDisabled>
<outOfOrder>true</outOfOrder>
<baselineOnMigrate>true</baselineOnMigrate>
</configuration>
</plugin>
配置项目说明
? db.user、db.password、jdbc.url 为数据库的配置,这里使用变量的形式,因为我们不同环境的数据库配置都不一样的
? db/migration 配置了脚本的存放目录
? schema_version 配置了管理脚本在数据库的表名称
因为不同环境具有不同的数据库配置,所以我们还在Maven配置了不同的profiles,这里我们配置一个demo环境:
<profile>
<id>demo</id>
<properties>
<jdbc.url>jdbc:mysql://127.0.0.1:3306/anyin-demo?characterEncoding=UTF-8<![CDATA[&]]>useSSL=false<![CDATA[&]]>autoReconnect=true<![CDATA[&]]>allowMultiQueries=true</jdbc.url>
<db.user>root</db.user>
<db.password>rootroot</db.password>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
接着,我们在resources/db/migration目录下新增我们的数据库脚本,如下图:
? 这里我们使用不同的文件夹区分不同的版本迭代,例如这里是v1.0.0和v1.0.1版本,注意这里是用下划线
? SQL脚本的名称规范:版本_时间__文件描述.sql,时间建议到分钟即可,这样子多人开发的时候避免出现一样的时间戳或者文件名,注意在文件描述之前是两个下划线
最后,我们就可以通过mvn命令执行SQL脚本了,指令如下:
# mvn clean package
# mvn flyway:repair flyway:migrate
执行之后的打印下如下:
数据库新增的信息如下:
? 在执行脚本之前一定需要先执行package指令,把对应的SQL脚本放到target/classes目录下,Flyway是从该目录获取脚本进行执行的
? flyway:repair 是修复指令,使用场景是对于已经执行过的SQL脚本,后来开发人员又手动修改,这样子会导致文件的checksum值不一样,从而阻断SQL脚本的执行。这时候需要开发人员人工确认SQL脚本没问题,然后在执行该指令,这样子会修改对应数据库的checksum值,保证SQL脚本和数据库的执行记录是一致的
? flyway:migrate 在确认了前置工作已经准备就绪,则可以执行该指令,从而执行SQL脚本到数据库中
对于一般的单体项目或者小型项目,使用插件的方式没什么大问题,而对于分布式的微服务项目则不太合适。一般的分布式微服务都会把配置放入配置中心,项目启动的时候直接从配置中心读取对应的配置,而插件的方式是需要把数据库的账号密码写入pom.xml文件中,这样显然不合适。
为了解决这个问题,我们接着看第二个方案。
方法二:使用编码方式
Flyway除了提供Maven Plugin的方式,还提供对应的API,使得我们可以通过代码执行SQL脚本。
首先,需要添加flyway-core的依赖,如下:
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
接着,新增一个FlywayMigrate类,代码如下:
@Component
@Slf4j
public class FlywayMigrate implements InitializingBean {
@Value("${spring.datasource.druid.url}")
private String url;
@Value("${spring.datasource.druid.username}")
private String username;
@Value("${spring.datasource.druid.password}")
private String password;
@Value("${anyin.flyway.table}")
private String table;
@Value("${anyin.flyway.locations}")
private String[] locations;
@Override
public void afterPropertiesSet() throws Exception {
Flyway flyway = Flyway.configure()
.locations(locations)
.table(table)
.cleanDisabled(true)
.outOfOrder(true)
.baselineOnMigrate(true)
.dataSource(url, username, password)
.load();
flyway.repair();
flyway.migrate();
}
}
在微服务项目中,我们的配置都可以从配置中心获取,所以这里我们通过@Value注入对应的数据库配置,接着实现InitializingBean接口,在afterPropertiesSet方法实现我们的脚本执行逻辑。
该方式为编码方式,如果对于SQL脚本的执行有特殊需求的话(例如审核),则可以通过该方式进行定制化开发。如果没有特殊需求的话,那还是略显繁琐,其实spring-boot-autoconfigure组件已经为我们做了这种的事情
我们接着看第三个方案。
方法三:使用SpringBoot内置自动配置
在Spring Boot 中spring-boot-autoconfigure组件其实已经为我们做了关于Flyway自动化配置相关的事情了,我们只需要引入flyway-core的依赖即可,如下:
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
这样子在启动服务的时候,会自动为我们执行SQL脚本。启动打印日志如下:
最后
至此,通过Flyway管理脚本的3种方式已经分享完,如果有什么问题欢迎交流。
相关代码地址:
? https://gitee.com/anyin/shiro-to-token
? https://gitee.com/anyin/anyin-cloud
注意,对于生产环境而言,建议还是不要让Flyway自动执行,还是需要人工审核,否则某个人来个delete 没有where条件,那就背锅了
本文暂时没有评论,来添加一个吧(●'◡'●)