当前位置: 首页 > 编程笔记 >

SpringBoot使用flyway初始化数据库

谭彦
2023-03-14
本文向大家介绍SpringBoot使用flyway初始化数据库,包括了SpringBoot使用flyway初始化数据库的使用技巧和注意事项,需要的朋友参考一下

概述

Flyway这款数据库版本工具就算大家没有使用过但也略有耳闻了,SpringBoot对该款工具进行集成的框架可以让我们在启动SpringBoot应用时自动去找SQL版本文件进行比对执行,但在迁移或初始化时往往还是需要先手动进行下数据库的初始化配置,否则会把Unknown database的异常。 为了减少这一步所以个人就以SpringBoot的方式编码在项目的启动时自动进行数据库的初始化,然后再执行版本文件。

自动建库实现步骤

具体思路

  1. SpringBoot的配置项都会有相应的Properties属性类,数据库的属性类为DataSourceProperties,flyway的属性类为FlywayProperties,尽可能的使用其中的配置项而不额外添加自定义的配置
  2. 建库与相关设置的语句一般不会对已存在的设置进行更改(如建库建表时都是CREATE xxx IF NOT EXISTS),所以项目初始化时每次都执行也不会影响现有的数据库配置,编码时可以不用添加执行的前置判断

代码实现

配置文件

spring:
 profiles:
 include: database

application-database.yml

spring:
 datasource:
 url: jdbc:mysql://yourIp:3306/spring_boot_series?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&serverTimezone=GMT
 username: yourUsername
 password: yourPassword
 driver-class-name: com.mysql.cj.jdbc.Driver
 # 自动读取spring.datasource配置进行迁移操作
 flyway:
 # 版本迁移位置
 locations: classpath:db
 baseline-version: 1.0.2
 init-sqls:
 - SET @OLD_UNIQUE_CHECKS = @@UNIQUE_CHECKS, UNIQUE_CHECKS = 0;
 - SET @OLD_FOREIGN_KEY_CHECKS = @@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS = 0;
 - SET @OLD_SQL_MODE = @@SQL_MODE, SQL_MODE =
 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';
 - CREATE SCHEMA IF NOT EXISTS `spring_boot_series` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;

为了让项目的配置结构更清晰,所以我把数据库的相关配置都独立到application-database.yml中。
flyway的init-sqls配置是当获取到SQL statement时会执行SQL语句列表,但需要注意的是如果spring.datasource.url连接不上,该块语句是依旧无法被执行的,因为SpringBoot集成的flyway配置是通过spring.datasource的配置去连接数据库的,如果url中的数据库不存在,flyway的版本迁移就无法执行了。
前文提到尽可能的使用SpringBoot原有的配置项,所以init-sqls其实是我配给自己用的。 个人通过init-sqls配置初始化语句与其它方式配置初始化想到的好处:

  • 无需将初始化语句硬编码再让Statement执行
  • 当数据库选型进行变更时只需再配置文件中进行修改相应的初始化语句
  • SpringBoot可以直接以字符串列表进行读取,开发过程中使用起来更加灵活,而不用去解析SQL文件

数据库初始化器DatabaseInitializer

package io.wilson.flyway;


import com.zaxxer.hikari.HikariDataSource;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.flyway.FlywayProperties;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * @author Wilson
 */
@Slf4j
@Component
@AllArgsConstructor
public class DatabaseInitializer {
 private final FlywayProperties flywayProperties;
 private final DataSourceProperties dataSourceProperties;

 @PostConstruct
 public void init() throws SQLException {
 log.info("DatabaseInitializer uses flyway init-sqls to initiate database");
 String url = dataSourceProperties.getUrl();
 // jdbc url最后一个 '/' 用于分割具体 schema?参数
 int lastSplitIndex = url.lastIndexOf('/');
 // 获取spring.datasource.url具体数据库schema前的jdbc url
 String addressUrl = url.substring(0, lastSplitIndex);
 // 直连数据库地址:jdbc:mysql://yourIp:port
 HikariDataSource dataSource = new HikariDataSource();
 dataSource.setJdbcUrl(addressUrl);
 dataSource.setUsername(dataSourceProperties.getUsername());
 dataSource.setPassword(dataSourceProperties.getPassword());
 Connection connection = dataSource.getConnection();
 Statement statement = connection.createStatement();
 for (String sql : flywayProperties.getInitSqls()) {
 // 通过flyway的init-sqls配置进行建库与数据库配置
 // executeUpdate:执行给定的SQL语句,该语句可以是INSERT,UPDATE或DELETE语句或不返回任何内容的SQL语句,例如SQL DDL语句。
 statement.executeUpdate(sql);
 }
 statement.close();
 connection.close();
 dataSource.close();
 log.info("DatabaseInitializer initialize completed");
 }
}

简单的主程序FlywayApplication

package io.wilson.flyway;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author Wilson
 */
@SpringBootApplication
@MapperScan("io.wilson.flyway.mapper")
public class FlywayApplication {
 public static void main(String[] args) {
 SpringApplication.run(FlywayApplication.class, args);
 }
}

执行效果图

当项目启动时可以看到DatabaseInitializer会先通过init-sqls进行数据库的初始化,然后SpringBoot再初始化通用的数据源并执行SQL版本文件。图中的create_database.sql文件存放的是init-sqls配置的语句,该文件不会被执行,可以忽略。


  • 如果对flyway不了解的可以看我之前的文章SpringBoot集成Flyway进行数据库版本迁移管理
  • 本文例子仓库:spring-bootflyway-demo
  • flyway官网文档

以上就是SpringBoot使用flyway初始化数据库的详细内容,更多关于SpringBoot 初始化数据库的资料请关注小牛知识库其它相关文章!

 类似资料:
  • 我有不使用Flyway的现有数据库postgres,我需要复制它。如何将现有数据库状态移动到新的空数据库?我没有任何迁移sql。所以我期待像Liquibase中的GenerateChangelog这样的命令,但在Flyway中似乎没有这样的命令。

  • 我想为现有的应用程序使用flyway。 应该有两种不同的情况: 1)应用程序安装:DDL和数据库初始化 2) 应用程序更新:迁移数据库 问题是如果我安装版本6.0,我有例如: 如果我将init version设置为V1.0.0,它将执行直到V6_0_0的所有更新,但是在数据库初始化之后,它将跳过所有更新。 要安装一个旧的shema,这样我就可以使用所有udpate脚本,即使对于全新安装也会非常困难

  • 我有一个Java Spring Boot应用程序,在我的Maven pom.xml中将Flyway配置为依赖项(我有一个父pom和一个项目pom...Flyway是在我的项目pom中定义的)。 application.properties中只有几个条目: 我可以运行一个maven任务来让Flyway运行来创建/更新我的数据库,然后针对该数据库运行我的应用程序,但是我很难通过运行我的应用程序(这在p

  • 我在读关于Flyway的文件时发现: 如果您有一个尚未被Flyway填充的现有数据库,则可以这样做: 而我的问题是,我可以用特定版本初始化元数据表吗? 诸如此类: 在db/migration文件夹下,我有一些从1.0到1.49的sql脚本;触针位于1.35。其目的是在1.35中初始化prod版本,而不创建初始迁移脚本(由于几个原因,我无法创建它…)并在迁移期间应用1.36到1.49之间的sql脚本

  • 初始化数据 打开MainSetup类,在Daos语句后面插入新建根用户的代码 // 初始化默认根用户 if (dao.count(User.class) == 0) { User user = new User(); user.setName("admin"); user.setPassword

  • 我有以下docker compose文件(): 以及下面的: 然后执行以下命令: 它会导致错误: 在日志中,我看到以下内容: 看起来flyway在数据库初始化之前启动,因此无法连接到数据库,我看到下面的错误。 我怎样才能解决这个问题? 我谷歌了类似的问题,我找到了以下建议:https://github.com/vishnubob/wait-for-it但我是docker的新手,我不明白如何将其放入