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 初始化數據庫的資料請關註WalkonNet其它相關文章!

推薦閱讀: