数据库的管理和迁移
文章目录
一: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): 可以执行多次,包含描述和校验和(没有版本);主要用于视图,存储过程,函数等
- 前缀:
- V 代表版本变迁(Versioned Migrations)
- U 代表撤销变迁(Undo Migrations) < ----- 撤销变迁(Undo Migrations)在收费版本中
- R 代表可重复变迁(Repeatable Migrations)
- 版本号: 唯一的版本号,比如V1.0.1
- 分隔符: __ (两个下划线)
- 描述信息: 描述信息
- 后缀: .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 提供基本的回滚支持,但通常建议通过手动编写回滚脚本来管理回滚操作。
- 学习曲线:需要学习如何编写和管理迁移脚本。
- 性能开销:在大型数据库上应用大量变更可能会影响性能。
- 复杂性:对于复杂的变更,迁移脚本可能会变得复杂和难以维护。