diff --git a/lab-20/lab-20-database-version-control-flyway/pom.xml b/lab-20/lab-20-database-version-control-flyway/pom.xml index faaa9fa3..c243f384 100644 --- a/lab-20/lab-20-database-version-control-flyway/pom.xml +++ b/lab-20/lab-20-database-version-control-flyway/pom.xml @@ -14,6 +14,7 @@ + org.springframework.boot spring-boot-starter-jdbc @@ -24,10 +25,10 @@ 5.1.48 + org.flywaydb flyway-core - 5.2.4 diff --git a/lab-20/lab-20-database-version-control-flyway/src/main/java/cn/iocoder/springboot/lab20/databaseversioncontrol/migration/ExampleFlywayCallback.java b/lab-20/lab-20-database-version-control-flyway/src/main/java/cn/iocoder/springboot/lab20/databaseversioncontrol/migration/ExampleFlywayCallback.java new file mode 100644 index 00000000..659392f9 --- /dev/null +++ b/lab-20/lab-20-database-version-control-flyway/src/main/java/cn/iocoder/springboot/lab20/databaseversioncontrol/migration/ExampleFlywayCallback.java @@ -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); + } + +} diff --git a/lab-20/lab-20-database-version-control-flyway/src/main/java/cn/iocoder/springboot/lab20/databaseversioncontrol/migration/V1_1__FixUsername.java b/lab-20/lab-20-database-version-control-flyway/src/main/java/cn/iocoder/springboot/lab20/databaseversioncontrol/migration/V1_1__FixUsername.java new file mode 100644 index 00000000..74b9a3d3 --- /dev/null +++ b/lab-20/lab-20-database-version-control-flyway/src/main/java/cn/iocoder/springboot/lab20/databaseversioncontrol/migration/V1_1__FixUsername.java @@ -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(); // 默认按照约定的规则,从类名中解析获得。可以自定义 + } + +} diff --git a/lab-20/lab-20-database-version-control-flyway/src/main/resources/application.yaml b/lab-20/lab-20-database-version-control-flyway/src/main/resources/application.yaml index c4041265..ff316839 100644 --- a/lab-20/lab-20-database-version-control-flyway/src/main/resources/application.yaml +++ b/lab-20/lab-20-database-version-control-flyway/src/main/resources/application.yaml @@ -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: # 数据库密码 diff --git a/lab-20/lab-20-database-version-control-flyway/src/main/resources/db/migration/V1.0__INIT_DB.sql b/lab-20/lab-20-database-version-control-flyway/src/main/resources/db/migration/V1.0__INIT_DB.sql index 02a9b8eb..10a494ab 100644 --- a/lab-20/lab-20-database-version-control-flyway/src/main/resources/db/migration/V1.0__INIT_DB.sql +++ b/lab-20/lab-20-database-version-control-flyway/src/main/resources/db/migration/V1.0__INIT_DB.sql @@ -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()); diff --git a/lab-20/lab-20-database-version-control-liquibase/pom.xml b/lab-20/lab-20-database-version-control-liquibase/pom.xml new file mode 100644 index 00000000..4e978c99 --- /dev/null +++ b/lab-20/lab-20-database-version-control-liquibase/pom.xml @@ -0,0 +1,35 @@ + + + + org.springframework.boot + spring-boot-starter-parent + 2.1.3.RELEASE + + + 4.0.0 + + lab-20-database-version-control-liquibase + + + + + + org.springframework.boot + spring-boot-starter-jdbc + + + mysql + mysql-connector-java + + + + + + org.liquibase + liquibase-core + + + + diff --git a/lab-20/lab-20-database-version-control-liquibase/src/main/java/cn/iocoder/springboot/lab20/databaseversioncontrol/Application.java b/lab-20/lab-20-database-version-control-liquibase/src/main/java/cn/iocoder/springboot/lab20/databaseversioncontrol/Application.java new file mode 100644 index 00000000..ebb6f948 --- /dev/null +++ b/lab-20/lab-20-database-version-control-liquibase/src/main/java/cn/iocoder/springboot/lab20/databaseversioncontrol/Application.java @@ -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); + } + +} diff --git a/lab-20/lab-20-database-version-control-liquibase/src/main/java/cn/iocoder/springboot/lab20/databaseversioncontrol/migration/CHANGE_SET_3_FixUsername.java b/lab-20/lab-20-database-version-control-liquibase/src/main/java/cn/iocoder/springboot/lab20/databaseversioncontrol/migration/CHANGE_SET_3_FixUsername.java new file mode 100644 index 00000000..c331cf7b --- /dev/null +++ b/lab-20/lab-20-database-version-control-liquibase/src/main/java/cn/iocoder/springboot/lab20/databaseversioncontrol/migration/CHANGE_SET_3_FixUsername.java @@ -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; + } + +} diff --git a/lab-20/lab-20-database-version-control-liquibase/src/main/resources/application.yaml b/lab-20/lab-20-database-version-control-liquibase/src/main/resources/application.yaml new file mode 100644 index 00000000..eb76689b --- /dev/null +++ b/lab-20/lab-20-database-version-control-liquibase/src/main/resources/application.yaml @@ -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: # 数据库密码 diff --git a/lab-20/lab-20-database-version-control-liquibase/src/main/resources/db/changelog/db.changelog-master-bak.yaml b/lab-20/lab-20-database-version-control-liquibase/src/main/resources/db/changelog/db.changelog-master-bak.yaml new file mode 100644 index 00000000..7935ec2f --- /dev/null +++ b/lab-20/lab-20-database-version-control-liquibase/src/main/resources/db/changelog/db.changelog-master-bak.yaml @@ -0,0 +1 @@ +databaseChangeLog: diff --git a/lab-20/lab-20-database-version-control-liquibase/src/main/resources/db/changelog/db.changelog-master.yaml b/lab-20/lab-20-database-version-control-liquibase/src/main/resources/db/changelog/db.changelog-master.yaml new file mode 100644 index 00000000..64e9f4bc --- /dev/null +++ b/lab-20/lab-20-database-version-control-liquibase/src/main/resources/db/changelog/db.changelog-master.yaml @@ -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 diff --git a/lab-20/lab-20-database-version-control-liquibase/src/main/resources/db/changelog/sqlfile/CHAGE_SET_2_INIT_DB.sql b/lab-20/lab-20-database-version-control-liquibase/src/main/resources/db/changelog/sqlfile/CHAGE_SET_2_INIT_DB.sql new file mode 100644 index 00000000..327cdcf1 --- /dev/null +++ b/lab-20/lab-20-database-version-control-liquibase/src/main/resources/db/changelog/sqlfile/CHAGE_SET_2_INIT_DB.sql @@ -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()); diff --git a/lab-20/pom.xml b/lab-20/pom.xml index 8403ca71..5d21b3b7 100644 --- a/lab-20/pom.xml +++ b/lab-20/pom.xml @@ -14,6 +14,7 @@ lab-20-database-version-control lab-20-database-version-control-flyway + lab-20-database-version-control-liquibase