Spring Boot - 实用功能11 - 数据库管理和迁移

数据库的管理和迁移

一:Liquibase对数据库管理和迁移

1:什么是Liquibase

Liquibase 是一个开源的数据库变更管理工具,用于跟踪、管理和部署数据库结构的变化。

它支持多种数据库(如 MySQL、PostgreSQL、Oracle、SQL Server 等),并且可以通过多种格式(如 XML、YAML、JSON、SQL 等)来定义数据库变更。

Liquibase 的主要目标是确保数据库 schema 在不同环境(开发、测试、生产)之间保持一致。

2:Liquibase优势

  • 支持几乎所有主流的数据库,目前支持包括 Oracle/Sql Server/DB2/MySql/Sybase/PostgreSQL等,这样在数据库的部署和升级环节可帮助应用系统支持多数据库
  • 支持版本控制,这样就能支持多开发者的协作维护;
  • 日志文件支持多种格式,如XML, YAML, JSON, SQL等;
  • 提供变化应用的回滚功能,可按时间、数量或标签(tag)回滚已应用的变化。通过这种方式,开发人员可轻易的还原数据库在任何时间点的状态
  • 支持多种运行方式,如命令行、Spring集成、Maven插件、Gradle插件等。

3:为何会出现Liquibase这类工具呢

在实际上线的应用中,随着版本的迭代,经常会遇到需要变更数据库表和字段,必然会遇到需要对这些变更进行记录和管理,以及回滚等等;

同时只有脚本化且版本可管理,才能在让数据库实现真正的DevOps(自动化执行 + 回滚等)。

在这样的场景下Liquibase等工具的出现也就成为了必然

4:Liquibase是如何工作的

变更集 - ChangeSet

  • 变更集是Liquibase 中的基本单元,每个变更集包含一组数据库操作(如创建表、添加列、修改数据等)
  • 每个变更集都有一个唯一的标识符(ID)、作者和描述

变更日志 - ChangeLog

  • 变更日志是包含多个变更集的文件,定义了整个数据库 schema 的变更历史。
  • 变更日志可以是 XML、YAML、JSON 或 SQL 文件。

变更日志锁(Databasechangeloglock)

  • Liquibase 在执行变更时会创建一个锁表(通常是 DATABASECHANGELOGLOCK),以确保在同一时间只有一个进程可以执行变更。
  • 这有助于防止并发变更导致的数据不一致问题

变更日志表(Databasechangelog)

  • Liquibase 会在数据库中创建一个 DATABASECHANGELOG 表,记录已经执行过的变更集
  • 这有助于 Liquibase 知道哪些变更已经应用,哪些变更需要应用。

变更日志锁表(Databasechangeloglock)

  • Liquibase 还会创建一个 DATABASECHANGELOGLOCK 表,用于管理变更过程中的锁。
  • 这确保了在同一时间只有一个 Liquibase 实例可以应用变更

执行变更

  • 当 Liquibase 执行变更时,它会读取变更日志文件,检查 DATABASECHANGELOG 表中已经应用的变更集。
  • 对于尚未应用的变更集,Liquibase 会按顺序执行这些变更集,并将执行结果记录在 DATABASECHANGELOG 表中。

在这里插入图片描述

5:spring boot使用实例

1:添加依赖

在 pom.xml 文件中添加 Liquibase 和数据库驱动的依赖。假设我们使用的是 MySQL 数据库:

<dependencies>
    <!-- Spring Boot Starter Data JPA -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <!-- MySQL Connector -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>

    <!-- Liquibase -->
    <dependency>
        <groupId>org.liquibase</groupId>
        <artifactId>liquibase-core</artifactId>
    </dependency>
</dependencies>

2:配置数据库的连接

# 主要是指定change-log的位置,默认的位置是classpath:/db/changelog/db.changelog-master.yaml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/test_db_liquibase?useSSL=false&autoReconnect=true&characterEncoding=utf8
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: bfXa4Pt2lUUScy8jakXf
  liquibase:
    enabled: true
    # 如下配置是被spring.datasource赋值的,所以可以不配置
#    url: jdbc:mysql://localhost:3306/test_db_liquibase?useSSL=false&autoReconnect=true&characterEncoding=utf8
#    user: root
#    password: bfXa4Pt2lUUScy8jakXf
    change-log: classpath:/db/changelog/db.changelog-master.yaml

在开发时,更多的配置可以从如下SpringBoot AutoConfig中找到

在这里插入图片描述

3:新增changelog

XML方式固然OK,不过依然推荐使用yml格式。

位置在classpath:/db/changelog/db.changelog-master.yaml中,取决于上面的定义

databaseChangeLog:
  - changeSet:
      id: 20240412-01
      author: cuihaida
      changes:
        - createTable:  # 声明要指定创建表的操作
            tableName: person # 要创建表的名称
            columns:  # 表的具体的列的说明
              - column:
                  name: id # id列,int类型,自增,主键,不能为空
                  type: int
                  autoIncrement: true
                  constraints:
                    primaryKey: true
                    nullable: false
              - column:
                  name: firstname # firstname列,字符串类型
                  type: varchar(50)
              - column:
                  name: lastname # firstname列,字符串类型,不能为空
                  type: varchar(50)
                  constraints:
                    nullable: false
              - column: # 状态列,字符串类型
                  name: state
                  type: char(2)

  - changeSet:
      id: 20240412-02
      author: cuihaida
      changes:
        - addColumn: # 当前的修改是增加列
            tableName: person # 对person表执行增加列的操作
            columns:
              - column:
                  name: username # 增加一个userName列,字符串类型
                  type: varchar(8)

  - changeSet:
      id: 20240412-03
      author: cuihaida
      changes:
        - addLookupTable:
            existingTableName: person
            existingColumnName: state
            newTableName: state
            newColumnName: id
            newColumnDataType: char(2)

  - changeSet:
      id: 20240412-04
      author: cuihaida
      changes:
        - sqlFile: # 指定sql file队当前的库进行修改
            splitStatements: true
            path: classpath:/db/changelog/db.changelog-20220412-04.sql # 指定sql的位置
            stripComments: true

🎉 还有哪些changeType?

在这里插入图片描述

如果重新启动这个SpringBootApplication,因为databasechangelog表中已经有相关执行记录了,所以将不再执行变更
🎉 比较好的实践方式就是yaml + sql_file

在这里插入图片描述

6:优缺点

优点

  • 版本控制:Liquibase 允许你将数据库变更作为代码进行版本控制,便于团队协作和回滚。
  • 跨平台:支持多种数据库,方便在不同环境中迁移和同步 schema。
  • 灵活:可以使用多种格式(XML、YAML、JSON、SQL)来定义变更集。
  • 自动化:集成到构建和部署流程中,自动化管理数据库变更。

缺点

  • 学习曲线:需要学习如何编写和管理变更集文件。
  • 性能开销:在大型数据库上应用大量变更可能会影响性能。
  • 复杂性:对于复杂的变更,变更集文件可能会变得复杂和难以维护。

二:flyway对数据库管理和迁移

1:概述和工作原理

Flyway是一款数据库迁移(migration)工具。

简单点说,就是在你部署应用的时候,帮你执行数据库脚本的工具。

Flyway支持SQL和Java两种类型的脚本,你可以将脚本打包到应用程序中,在应用程序启动时,由Flyway来管理这些脚本的执行

这些脚本被Flyway称之为migration。

本质上和liquibase机制一致。

按照verion的顺序(和数据库中的更新记录对比,找到未更新的),更新如下:

在这里插入图片描述

2:Flyway中的变迁(migrations)

对于Flyway,对数据库的所有更改都称为变迁(migrations),等同于liquibase中的changeset。

在Flyway中变迁(migrations)定义的更细,包含如下三种:

  • 版本变迁(Versioned Migrations): 每个版本执行一次,包含有版本、描述和校验和;常用于创建,修改,删除表;插入,修改数据等
  • 撤销变迁(Undo Migrations): 版本变迁(Versioned Migrations)的反操作。
  • 可重复变迁(Repeatable Migrations): 可以执行多次,包含描述和校验和(没有版本);主要用于视图,存储过程,函数等

在这里插入图片描述

  1. 前缀:
    1. V 代表版本变迁(Versioned Migrations)
    2. U 代表撤销变迁(Undo Migrations) < ----- 撤销变迁(Undo Migrations)在收费版本中
    3. R 代表可重复变迁(Repeatable Migrations)
  2. 版本号: 唯一的版本号,比如V1.0.1
  3. 分隔符: __ (两个下划线)
  4. 描述信息: 描述信息
  5. 后缀: .sql

3:flyway常用命令

Migrate: 是Flyway工作流的核心。

它将扫描文件系统或类路径以查找可用的Migrate。

它将把它们与已应用于数据库的Migrate进行比较。如果发现任何差异则迁移数据。

在这里插入图片描述

Clean: 清除掉对应数据库Schema中所有的对象,包括表结构,视图,存储过程等

clean操作在dev 和 test阶段很好用;(PS:不能用在product环境)

在这里插入图片描述

info:状态信息打印

用于打印所有的Migrations的详细和状态信息,也是通过MetaData和Migrations完成的,可以快速定位当前的数据库版本;

在这里插入图片描述

Validate: 验证以及apply的Migrations是否有变更,默认开启

原理是对比MetaData表与本地Migrations的checkNum值,如果值相同则验证通过,否则失败。

在这里插入图片描述

undo:Migrate的反操作, 即回滚操作,这是收费功能

在这里插入图片描述

BaseLine:对已经存在数据库Schema结构的数据库一种解决方案。

实现在非空数据库新建MetaData表,并把Migrations应用到该数据库;也可以应用到已有表结构的数据库中也可以实现添加Metadata表

在这里插入图片描述

repair:repair操作能够修复metaData表,该操作在metadata出现错误时很有用

在这里插入图片描述

4:spring boot使用实例

4.1:依赖和配置
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.28</version>
</dependency>
<dependency>
    <groupId>com.github.wenhao</groupId>
    <artifactId>jpa-spec</artifactId>
    <version>3.1.0</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<dependency>
    <groupId>org.flywaydb</groupId>
    <artifactId>flyway-mysql</artifactId>
    <version>8.5.7</version>
</dependency>
pring:
  datasource:
    url: jdbc:mysql://localhost:3306/test_db_flyway?useSSL=false&autoReconnect=true&characterEncoding=utf8
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: bfXa4Pt2lUUScy8jakXf
  flyway:
    enabled: true
    encoding: UTF-8
    # 可以支持多个location, 用','隔开
    locations: classpath:db/migration
    # migrate是否校验
    validate-on-migrate: true

更多的配置见这里

在这里插入图片描述

4.2:变更配置

在这里插入图片描述

V1.0__Init_DB.sql

DROP TABLE IF EXISTS `tb_user`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `tb_user` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `user_name` varchar(45) NOT NULL,
    `password` varchar(45) NOT NULL,
    `email` varchar(45) DEFAULT NULL,
    `phone_number` int(11) DEFAULT NULL,
    `description` varchar(255) DEFAULT NULL,
    `create_time` datetime DEFAULT NULL,
    `update_time` datetime DEFAULT NULL,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;

V1.1__Init_Data.sql

LOCK TABLES `tb_user` WRITE;
/*!40000 ALTER TABLE `tb_user` DISABLE KEYS */;
INSERT INTO `tb_user` VALUES (1,'pdai','dfasdf','suzhou.daipeng@gmail.com',1212121213,'afsdfsaf','2021-09-08 17:09:15','2021-09-08 17:09:15');
/*!40000 ALTER TABLE `tb_user` ENABLE KEYS */;
UNLOCK TABLES;
4.3:启动测试

在这里插入图片描述

5:进一步配置和高级功能

5.1:回滚支持

虽然 Flyway 提供基本的回滚支持,但通常建议通过手动编写回滚脚本来管理回滚操作。

可以在 src/main/resources/db/migration 目录下创建回滚脚本文件,例如 U1__Create_users_table.sql:

-- U1__Create_users_table.sql
DROP TABLE users;
5.2:使用 Java 进行迁移

除了 SQL 脚本,Flyway 还支持使用 Java 类进行迁移。这在需要复杂逻辑或调用外部服务时非常有用。

创建一个 Java 迁移类 V2__Add_column_to_users.java:

package com.example.demo.migration;

import org.flywaydb.core.api.migration.BaseJavaMigration;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;

public class V2__Add_column_to_users extends BaseJavaMigration {

    @Override
    public void migrate(JdbcTemplate jdbcTemplate) {
        jdbcTemplate.execute("ALTER TABLE users ADD COLUMN age INT");
    }
}

将这个类放在 src/main/java/com/example/demo/migration 目录下。

5.3:配置 Flyway 属性

Flyway 提供了许多配置属性,可以根据需要进行配置。

例如,可以配置 Flyway 不自动启动,而是通过编程方式启动:

spring:
	flyway:
		enabled: false

然后在 Spring Boot 应用中通过编程方式启动 Flyway:

import org.flywaydb.core.Flyway;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FlywayConfig {

    @Value("${spring.datasource.url}")
    private String url;

    @Value("${spring.datasource.username}")
    private String username;

    @Value("${spring.datasource.password}")
    private String password;

    @Bean(initMethod = "migrate")
    public Flyway flyway() {
        return Flyway.configure()
                .dataSource(url, username, password)
                .locations("classpath:db/migration")
                .load();
    }
}
5.4:使用 Flyway 命令行工具

Flyway 还提供了命令行工具,可以独立于 Spring Boot 应用来执行迁移。

下载 Flyway 命令行工具并配置数据库连接信息:

# flyway.conf
flyway.url=jdbc:mysql://localhost:3306/mydatabase
flyway.user=root
flyway.password=root
flyway.locations=filesystem:/path/to/migrations

然后运行迁移命令:

./flyway migrate

6:优缺点

优点

  • 简单易用:Flyway 使用 SQL 脚本定义迁移,易于理解和编写。
  • 版本控制:允许你将数据库变更作为代码进行版本控制,便于团队协作和回滚。
  • 跨平台:支持多种数据库,方便在不同环境中迁移和同步 schema。
  • 自动化:集成到构建和部署流程中,自动化管理数据库变更。
  • 轻量级:相对于其他数据库迁移工具,Flyway 更加轻量级和易于配置。

缺点

  • 回滚支持有限:Flyway 提供基本的回滚支持,但通常建议通过手动编写回滚脚本来管理回滚操作。
  • 学习曲线:需要学习如何编写和管理迁移脚本。
  • 性能开销:在大型数据库上应用大量变更可能会影响性能。
  • 复杂性:对于复杂的变更,迁移脚本可能会变得复杂和难以维护。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值