增加数据库版本管理示例

This commit is contained in:
YunaiV
2019-11-13 22:59:02 +08:00
parent 45dac8e872
commit 2a20f21b3c
13 changed files with 298 additions and 9 deletions

View File

@@ -14,6 +14,7 @@
<dependencies>
<!-- 实现对数据库连接池的自动化配置 -->
<!-- 同时spring-boot-starter-jdbc 支持 Flyway 的自动化配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
@@ -24,10 +25,10 @@
<version>5.1.48</version>
</dependency>
<!-- Flyway 依赖 -->
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
<version>5.2.4</version>
</dependency>
</dependencies>

View File

@@ -0,0 +1,30 @@
package cn.iocoder.springboot.lab20.databaseversioncontrol.migration;
import org.flywaydb.core.api.callback.Callback;
import org.flywaydb.core.api.callback.Context;
import org.flywaydb.core.api.callback.Event;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
public class ExampleFlywayCallback implements Callback {
private Logger log = LoggerFactory.getLogger(getClass());
@Override
public boolean supports(Event event, Context context) {
return true;
}
@Override
public boolean canHandleInTransaction(Event event, Context context) {
return false;
}
@Override
public void handle(Event event, Context context) {
log.info("event: {}", event);
}
}

View File

@@ -0,0 +1,55 @@
package cn.iocoder.springboot.lab20.databaseversioncontrol.migration;
import org.flywaydb.core.api.MigrationVersion;
import org.flywaydb.core.api.migration.BaseJavaMigration;
import org.flywaydb.core.api.migration.Context;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowCallbackHandler;
import java.sql.ResultSet;
import java.sql.SQLException;
public class V1_1__FixUsername extends BaseJavaMigration {
private Logger logger = LoggerFactory.getLogger(getClass());
@Override
public void migrate(Context context) throws Exception {
// 创建 JdbcTemplate ,方便 JDBC 操作
JdbcTemplate template = new JdbcTemplate(context.getConfiguration().getDataSource());
// 查询所有用户,如果用户名为 yudaoyuanma ,则变更成 yutou
template.query("SELECT id, username, password, create_time FROM users", new RowCallbackHandler() {
@Override
public void processRow(ResultSet rs) throws SQLException {
// 遍历返回的结果
do {
String username = rs.getString("username");
if ("yudaoyuanma".equals(username)) {
Integer id = rs.getInt("id");
template.update("UPDATE users SET username = ? WHERE id = ?",
"yutou", id);
logger.info("[migrate][更新 user({}) 的用户名({} => {})", id, username, "yutou");
}
} while (rs.next());
}
});
}
@Override
public Integer getChecksum() {
return 11; // 默认返回,是 null 。
}
@Override
public boolean canExecuteInTransaction() {
return true; // 默认返回,也是 true
}
@Override
public MigrationVersion getVersion() {
return super.getVersion(); // 默认按照约定的规则,从类名中解析获得。可以自定义
}
}

View File

@@ -1,15 +1,18 @@
spring:
# datasource 数据源配置内容,对应 DataSourceProperties 配置属性类
datasource:
url: jdbc:mysql://127.0.0.1:3306/lab-19-flyway?useSSL=false&useUnicode=true&characterEncoding=UTF-8
url: jdbc:mysql://127.0.0.1:3306/lab-20-flyway?useSSL=false&useUnicode=true&characterEncoding=UTF-8
driver-class-name: com.mysql.jdbc.Driver
username: root # 数据库账号
password: # 数据库密码
# flyway 配置内容,对应 FlywayAutoConfiguration.FlywayConfiguration 配置项
flyway:
enabled: true
baseline-on-migrate: true
locations: classpath:db/migration
url: jdbc:mysql://127.0.0.1:3306/lab-19-flyway?useSSL=false&useUnicode=true&characterEncoding=UTF-8
username: root
password:
enabled: true # 开启 Flyway 功能
cleanDisabled: true # 禁用 Flyway 所有的 drop 相关的逻辑,避免出现跑路的情况。
locations: # 迁移脚本目录
- classpath:db/migration # 配置 SQL-based 的 SQL 脚本在该目录下
- classpath:cn.iocoder.springboot.lab20.databaseversioncontrol.migration # 配置 Java-based 的 Java 文件在该目录下
check-location: false # 是否校验迁移脚本目录下。如果配置为 true ,代表需要校验。此时,如果目录下没有迁移脚本,会抛出 IllegalStateException 异常
url: jdbc:mysql://127.0.0.1:3306/lab-20-flyway?useSSL=false&useUnicode=true&characterEncoding=UTF-8 # 数据库地址
user: root # 数据库账号
password: # 数据库密码

View File

@@ -1,3 +1,4 @@
-- 创建用户表
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户编号',
`username` varchar(64) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '账号',
@@ -6,3 +7,6 @@ CREATE TABLE `users` (
PRIMARY KEY (`id`),
UNIQUE KEY `idx_username` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
-- 插入一条数据
INSERT INTO `users`(username, password, create_time) VALUES('yudaoyuanma', 'password', now());

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>lab-20-database-version-control-liquibase</artifactId>
<dependencies>
<!-- 实现对数据库连接池的自动化配置 -->
<!-- 同时spring-boot-starter-jdbc 支持 Liquibase 的自动化配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency> <!-- 本示例,我们使用 MySQL -->
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<!-- <version>5.1.48</version>-->
</dependency>
<!-- Liquibase 依赖 -->
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,14 @@
package cn.iocoder.springboot.lab20.databaseversioncontrol;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
// 启动 Spring Boot 应用
SpringApplication.run(Application.class, args);
}
}

View File

@@ -0,0 +1,57 @@
package cn.iocoder.springboot.lab20.databaseversioncontrol.migration;
import liquibase.change.custom.CustomTaskChange;
import liquibase.database.Database;
import liquibase.database.jvm.JdbcConnection;
import liquibase.exception.CustomChangeException;
import liquibase.exception.SetupException;
import liquibase.exception.ValidationErrors;
import liquibase.resource.ResourceAccessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class CHANGE_SET_3_FixUsername implements CustomTaskChange {
private Logger logger = LoggerFactory.getLogger(getClass());
@Override
public void execute(Database database) throws CustomChangeException {
JdbcConnection connection = (JdbcConnection) database.getConnection();
try (PreparedStatement psmt = connection.prepareStatement("SELECT id, username, password, create_time FROM users")) {
try (ResultSet rs = psmt.executeQuery()) {
while (rs.next()) {
String username = rs.getString("username");
if ("yudaoyuanma".equals(username)) {
Integer id = rs.getInt("id");
// 这里,再来一刀更新操作,偷懒不写了。
logger.info("[migrate][更新 user({}) 的用户名({} => {})", id, username, "yutou");
}
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public String getConfirmationMessage() {
return null;
}
@Override
public void setUp() throws SetupException {
}
@Override
public void setFileOpener(ResourceAccessor resourceAccessor) {
}
@Override
public ValidationErrors validate(Database database) {
return null;
}
}

View File

@@ -0,0 +1,14 @@
spring:
# datasource 数据源配置内容,对应 DataSourceProperties 配置属性类
datasource:
url: jdbc:mysql://127.0.0.1:3306/lab-20-liquibase?useSSL=false&useUnicode=true&characterEncoding=UTF-8
driver-class-name: com.mysql.jdbc.Driver
username: root # 数据库账号
password: # 数据库密码
# Liquibase 配置内容,对应 LiquibaseProperties 配置项
liquibase:
enabled: true # 开启 Liquibase 功能。默认为 true 。
change-log: classpath:/db/changelog/db.changelog-master.yaml # Liquibase 配置文件地址
url: jdbc:mysql://127.0.0.1:3306/lab-20-liquibase?useSSL=false&useUnicode=true&characterEncoding=UTF-8 # 数据库地址
user: root # 数据库账号
password: # 数据库密码

View File

@@ -0,0 +1,62 @@
databaseChangeLog:
- changeSet: # 对应一个 ChangeSet 对象
id: 0 # ChangeSet 编号
author: yunai # 作者
comments: # 备注
- changeSet: # 对应一个 ChangeSet 对象
id: 1 # ChangeSet 编号
author: yunai # 作者
comments: 初始化 users 表 # 备注
changes: # 对应 Change 数组。Change 是一个接口,每种操作对应一种 Change 实现类
- createTable: # 创建表,对应 CreateTableChange 对象。
tableName: users # 表名
remarkds: 用户表 # 表注释
columns: # 对应 ColumnConfig 数组
- column:
name: id # 字段名
type: int # 字段类型
autoIncrement: true # 自增
constraints: # 限制条件,对应一个 ConstraintsConfig 对象
primaryKey: true # 主键
nullable: false # 不允许空
- column:
name: username
type: varchar(64)
constraints:
nullable: false
- column:
name: password
type: varchar(32)
constraints:
nullable: false
- column:
name: create_time
type: datetime
constraints:
nullable: false
- insert: # 插入记录,对应 InsertDataChange 对象。
tableName: users # 表名
columns: # 对应 ColumnConfig 数组
- column:
name: username # 字段名
value: yudaoyuanma # 值
- column:
name: password
value: password
- column:
name: create_time
value: now()
- changeSet: # 对应一个 ChangeSet 对象
id: 2 # ChangeSet 编号
author: yunai # 作者
comments: 初始化 users2 表 # 备注
changes: # 对应 Change 数组。Change 是一个接口,每种操作对应一种 Change 实现类
- sqlFile: # 使用 SQL 文件,对应 SQLFileChange 对象
encoding: utf8
path: classpath:db/changelog/sqlfile/CHAGE_SET_2_INIT_DB.sql
- changeSet: # 对应一个 ChangeSet 对象
id: 3 # ChangeSet 编号
author: yunai # 作者
comments: 修复 `users` 的用户名 # 备注
changes: # 对应 Change 数组。Change 是一个接口,每种操作对应一种 Change 实现类
- customChange: {class: cn.iocoder.springboot.lab20.databaseversioncontrol.migration.CHANGE_SET_3_FixUsername} # 对应 CustomTaskChange

View File

@@ -0,0 +1,12 @@
-- 创建用户表
CREATE TABLE `users2` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户编号',
`username` varchar(64) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '账号',
`password` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '密码',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_username` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
-- 插入一条数据
INSERT INTO `users2`(username, password, create_time) VALUES('yudaoyuanma', 'password', now());

View File

@@ -14,6 +14,7 @@
<modules>
<module>lab-20-database-version-control</module>
<module>lab-20-database-version-control-flyway</module>
<module>lab-20-database-version-control-liquibase</module>
</modules>