SpringBoot使用flyway初始化数据库
作者:WilsonHe 发布时间:2024-01-28 13:43:38
目录
概述
自动建库实现步骤
具体思路
代码实现
数据库初始化器DatabaseInitializer
简单的主程序FlywayApplication
执行效果图
附
概述
Flyway这款数据库版本工具就算大家没有使用过但也略有耳闻了,SpringBoot对该款工具进行集成的框架可以让我们在启动SpringBoot应用时自动去找SQL版本文件进行比对执行,但在迁移或初始化时往往还是需要先手动进行下数据库的初始化配置,否则会把Unknown database的异常。 为了减少这一步所以个人就以SpringBoot的方式编码在项目的启动时自动进行数据库的初始化,然后再执行版本文件。
自动建库实现步骤
具体思路
SpringBoot的配置项都会有相应的Properties属性类,数据库的属性类为DataSourceProperties,flyway的属性类为FlywayProperties,尽可能的使用其中的配置项而不额外添加自定义的配置
建库与相关设置的语句一般不会对已存在的设置进行更改(如建库建表时都是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官网文档
来源:https://juejin.cn/post/6935353661052682247


猜你喜欢
- 本文实例讲述了Python3.5实现的 * 菜单功能。分享给大家供大家参考,具体如下:程序: * 菜单要求:
- 方法一:巧用sum函数将list列表与一个空列表相加,就能把嵌套列表合并成一个a=[[1],[2],[3],[4],[5]]merge=su
- 前言最近在研究 pyecharts 的用法,它是 python 的一个可视化工具,然后就想着结合微信来一起玩不多说,直接看效果:
- 用途:图形化界面操作:通过设计一个图形化的界面,用户可以通过按钮或其他操作方式调用后台的Python程序进行数据处理、图像处理等功能。自动化
- Python是一种计算机程序设计语言,一种面向对象的动态类型语言,一种脚本语言。最初被设计用于编写自动化脚本(shell)的,常用于各种服务
- 备注:Ken Henderson 从开发者的角度来阐述了SQL SERVER 2000内存管理的内部机制简介在本专栏中,我们将从一个开发者的
- 先按照下面的表结构创建mysql_order_by_test数据表,我们用实例一点一点告诉你,MySQL order by的用法。ORDER
- 背景最近本菜鸡在学习 python GUI,从 tkinter 入门,想先做个小软件练习一下思来想去,决定做一个 计算器设计思路首先,导入我
- 1 任务需求  首先,我们来明确一下本文所需实现的需求。  现有一个
- 一、数据库介绍1、为什么要学习数据库通常,我们存储数据,直接用本地文件即可,但是,本地文件不利于存放海量数据,也不利于用程序对文件的数据进行
- 今天遇到一个奇怪的现象,使用tensorflow-gpu的时候,出现内存超额~~如果我训练什么大型数据也就算了,关键我就写了一个y=W*x…
- 首先呢,我们来看看一般项目路由是怎么划分的。为什么这么划分呢?如果大项目业务非常多,单纯的单页面很难维护,我们只有这样规范化,才能高效率。模
- 目标:爬取自己账号中购买的课程视频。一、实现登录账号这里采用的是手动输入验证码的方式,有能力的盆友也可以通过图像识别的方式自动填写验证码。登
- 之前一直正常的项目,莫名其妙的 database/sql 包下的方法、结构体等等IDE都无法识别,出现一堆Unresolved refere
- 前言MySQL 事务隔离级别是为了解决并发事务互相干扰的问题的,MySQL 事务隔离级别总共有以下 4 种:READ UNCOMMITTED
- 该平台会集成UI自动化及api自动化,里面也会涉及到一些简单的HTML等前端,当然都是很基础的东西。在以后的博客里,我会一点点的尽量写详细,
- 在新旧版的torch中的傅里叶变换函数在定义和用法上存在不同,记录一下。1、旧版fft = torch.rfft(input, 2, nor
- 一个JavaScript代码编写的图片展示特效,效果很棒。效果图:演示:<!DOCTYPE HTML PUBLIC "-//
- 问题现象元素的属性中没有id、name;虽然有class,但比较大众化,且位置也不固定;例如:页码中的下一页;那该如何找到该元素?<a
- 概述最近在一家公司实习,入职第一个大一点的需求是将公司开发的两个winstore app的排名信息进行可视化。大概挑选了下,排除了Flask