chore(scratch): 两库合并的探针与做法留档
把本机开发库与服务器库并到一起时用到的探针、迁移前的 flyway 历史快照与做法说明一起入库,
下次再遇到库漂移不用重新摸索:结构摘要、逐行比对、差异行打印、并集插入、Flyway 的只读与迁移入口。
同时补了忽略规则:探针的临时输出,以及为分批应用迁移拷出来的迁移副本(入库会与真迁移混淆)。
备份(含会话令牌与手机号)此前已挡住。
做法与冲突判定规则见 .scratch/db-merge/README.md。
| | |
| | | |
| | | # 数据库备份(含会话令牌、用户手机号等)绝不提交。 |
| | | .scratch/**/backup/ |
| | | |
| | | # 探针的临时输出,以及为「分批应用迁移」而拷的迁移副本——副本入库会与真迁移混淆。 |
| | | .scratch/**/out/ |
| | | .scratch/**/dryrun-migrations/ |
| New file |
| | |
| | | import java.sql.Connection; |
| | | import java.sql.DriverManager; |
| | | import java.sql.PreparedStatement; |
| | | import java.sql.ResultSet; |
| | | import java.util.ArrayList; |
| | | import java.util.LinkedHashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.TreeMap; |
| | | |
| | | /** |
| | | * 只读探针:只打印某张表有差异的行——仅左库有 / 仅右库有 / 同主键但内容不同(两侧并列)。 |
| | | * |
| | | * <p>用法:java DiffRows <左url> <右url> <表名> <展示列,展示列...> |
| | | */ |
| | | public class DiffRows { |
| | | |
| | | public static void main(String[] args) throws Exception { |
| | | String table = args[2]; |
| | | String[] columns = args[3].split(","); |
| | | try (Connection left = DriverManager.getConnection(args[0], "root", "123456"); |
| | | Connection right = DriverManager.getConnection(args[1], "root", "123456")) { |
| | | Map<String, String> leftRows = rows(left, table, columns); |
| | | Map<String, String> rightRows = rows(right, table, columns); |
| | | System.out.println("== " + table + ":仅左库(本机 dev)有 =="); |
| | | for (Map.Entry<String, String> entry : leftRows.entrySet()) { |
| | | if (!rightRows.containsKey(entry.getKey())) System.out.println(" " + entry.getValue()); |
| | | } |
| | | System.out.println("== " + table + ":仅右库(服务器)有 =="); |
| | | for (Map.Entry<String, String> entry : rightRows.entrySet()) { |
| | | if (!leftRows.containsKey(entry.getKey())) System.out.println(" " + entry.getValue()); |
| | | } |
| | | System.out.println("== " + table + ":同主键内容不同 =="); |
| | | for (Map.Entry<String, String> entry : leftRows.entrySet()) { |
| | | String other = rightRows.get(entry.getKey()); |
| | | if (other == null || other.equals(entry.getValue())) continue; |
| | | System.out.println(" 左 " + entry.getValue()); |
| | | System.out.println(" 右 " + other); |
| | | System.out.println(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private static Map<String, String> rows(Connection connection, String table, String[] columns) throws Exception { |
| | | Map<String, String> lines = new TreeMap<>(); |
| | | String selection = String.join(", ", java.util.Arrays.stream(columns).map(c -> "`" + c + "`").toList()); |
| | | try (PreparedStatement statement = connection.prepareStatement( |
| | | "select id, " + selection + " from `" + table + "`"); |
| | | ResultSet result = statement.executeQuery()) { |
| | | while (result.next()) { |
| | | StringBuilder line = new StringBuilder("#" + result.getObject(1)); |
| | | for (int index = 0; index < columns.length; index++) { |
| | | Object value = result.getObject(index + 2); |
| | | String text = value == null ? "NULL" : String.valueOf(value); |
| | | if (text.length() > 70) text = text.substring(0, 70) + "…"; |
| | | line.append(" | ").append(columns[index]).append('=').append(text); |
| | | } |
| | | lines.put(String.valueOf(result.getObject(1)), line.toString()); |
| | | } |
| | | } |
| | | return new LinkedHashMap<>(lines); |
| | | } |
| | | } |
| New file |
| | |
| | | import org.flywaydb.core.Flyway; |
| | | import org.flywaydb.core.api.MigrationInfo; |
| | | |
| | | /** |
| | | * Flyway 探针:默认只读(info),带 --migrate 才真的执行迁移。 |
| | | * |
| | | * <p>用法:java FlywayProbe <jdbc-url> [--migrate] [--locations=filesystem:...] [--no-validate] |
| | | */ |
| | | public class FlywayProbe { |
| | | |
| | | public static void main(String[] args) { |
| | | String url = args[0]; |
| | | boolean migrate = false; |
| | | boolean validate = true; |
| | | String locations = "classpath:db/migration"; |
| | | boolean outOfOrder = false; |
| | | for (String arg : args) { |
| | | if ("--migrate".equals(arg)) migrate = true; |
| | | if ("--no-validate".equals(arg)) validate = false; |
| | | if ("--out-of-order".equals(arg)) outOfOrder = true; |
| | | if (arg.startsWith("--locations=")) locations = arg.substring("--locations=".length()); |
| | | } |
| | | Flyway flyway = Flyway.configure() |
| | | .dataSource(url, "root", "123456") |
| | | .locations(locations) |
| | | .baselineOnMigrate(true) |
| | | .validateOnMigrate(validate) |
| | | .outOfOrder(outOfOrder) |
| | | .load(); |
| | | |
| | | System.out.println("locations=" + locations + " validateOnMigrate=" + validate |
| | | + " outOfOrder=" + outOfOrder); |
| | | System.out.println("== CURRENT =="); |
| | | MigrationInfo current = flyway.info().current(); |
| | | System.out.println(" 已应用到: " + (current == null ? "(空)" : current.getVersion() + " " + current.getDescription())); |
| | | |
| | | System.out.println("== PENDING =="); |
| | | MigrationInfo[] pending = flyway.info().pending(); |
| | | for (MigrationInfo info : pending) { |
| | | System.out.println(" " + info.getVersion() + " | " + info.getDescription() + " | " + info.getType()); |
| | | } |
| | | System.out.println(" 共 " + pending.length + " 条待应用"); |
| | | |
| | | if (!migrate) { |
| | | System.out.println("(只读模式,未执行迁移)"); |
| | | return; |
| | | } |
| | | System.out.println("== MIGRATE =="); |
| | | try { |
| | | var result = flyway.migrate(); |
| | | System.out.println(" 应用了 " + result.migrationsExecuted + " 条,目标版本 " |
| | | + result.targetSchemaVersion + ",初始版本 " + result.initialSchemaVersion); |
| | | } catch (Exception exception) { |
| | | System.out.println(" !! 迁移失败:" + exception.getMessage()); |
| | | } |
| | | } |
| | | } |
| New file |
| | |
| | | import java.sql.Connection; |
| | | import java.sql.DriverManager; |
| | | import java.sql.ResultSet; |
| | | import java.sql.ResultSetMetaData; |
| | | import java.sql.Statement; |
| | | |
| | | /** |
| | | * 只读探针:执行一条查询并把结果按列打印出来(用于核对服务器上的数据现状)。 |
| | | * |
| | | * <p>用法:java Query <jdbc-url> "select ..." |
| | | */ |
| | | public class Query { |
| | | |
| | | public static void main(String[] args) throws Exception { |
| | | try (Connection connection = DriverManager.getConnection(args[0], "root", "123456"); |
| | | Statement statement = connection.createStatement(); |
| | | ResultSet rows = statement.executeQuery(args[1])) { |
| | | ResultSetMetaData meta = rows.getMetaData(); |
| | | int columns = meta.getColumnCount(); |
| | | StringBuilder header = new StringBuilder(); |
| | | for (int index = 1; index <= columns; index++) header.append(meta.getColumnLabel(index)).append(" | "); |
| | | System.out.println(header); |
| | | while (rows.next()) { |
| | | StringBuilder line = new StringBuilder(); |
| | | for (int index = 1; index <= columns; index++) { |
| | | Object value = rows.getObject(index); |
| | | line.append(value == null ? "NULL" : String.valueOf(value)).append(" | "); |
| | | } |
| | | System.out.println(line); |
| | | } |
| | | } |
| | | } |
| | | } |
| New file |
| | |
| | | # 两个数据库的合并:做法与工具 |
| | | |
| | | 本目录记录 2026-09-16 把**本机开发库**与**服务器库**并到一起的过程,以及可复现的工具与判定规则。 |
| | | 目录里的探针都是一次性只读/迁移工具,不是业务代码。 |
| | | |
| | | ## 当时的事实 |
| | | |
| | | | | 服务器库 `192.168.110.13:3306/talent_card` | 本机开发库 `127.0.0.1:8134/talent_card` | |
| | | | --- | --- | --- | |
| | | | MySQL | 5.7.44 | 8.0.36 | |
| | | | 表数 | 123(95 张迁移产物 + 28 张历史遗留表,后者代码已不引用) | 95(与迁移产物完全一致) | |
| | | | flyway | 启用,历史停在 V111 | **关闭**,`flyway_schema_history` 为空 | |
| | | | 结构缺口 | 缺 V112–V147(其中 V112/V113/V115/V119 会与手工列相撞) | 只缺 V147 的 6 列 | |
| | | |
| | | 结论:两边缺的都不只是本次改动——服务器库连合并前主线代码要的列(`benefit_order.collect_huifu_id`、 |
| | | `payment_transaction.funds_confirmation_status` 等)都没有,所以支付/核销/退款/进件在那里本来就跑不起来。 |
| | | |
| | | ## 工具 |
| | | |
| | | | 文件 | 用途 | |
| | | | --- | --- | |
| | | | `SchemaDigest.java` | 只读:打印一个库的结构摘要(flyway 历史、表、列、索引),用于两库比对 | |
| | | | `SchemaDump.java` | 只读:导出全部表的结构(`show create table`)或指定表的数据(INSERT),做备份 | |
| | | | `RunSqlFile.java` | 执行一个 .sql 文件,支持 `DELIMITER`(给本机库补单条迁移用) | |
| | | | `FlywayProbe.java` | Flyway 只读 `info`(默认)或 `--migrate`;可指定 locations 与 `--no-validate` | |
| | | | `RowCompare.java` | 只读:按主键逐行比对两库,报「同内容/内容不同/仅左/仅右」,**只比对共有的列** | |
| | | | `DiffRows.java` | 只读:把差异行按「仅左/仅右/同主键两侧并列」打印出来,用于判断是不是同一实体 | |
| | | | `SyncTool.java` | 两库按主键做**并集插入**(只插不改),`--dry-run` 可先看清单 | |
| | | | `Query.java` | 只读:执行一条查询并打印结果 | |
| | | | `restore-history.sql` | 迁移前服务器 `flyway_schema_history` 的快照(还原迁移账本用) | |
| | | |
| | | 编译与运行(classpath 复用模块的依赖清单): |
| | | |
| | | ```bash |
| | | cd talent-card-server && ./mvnw.cmd -o dependency:build-classpath -Dmdep.outputFile=target/cp.txt # cp.txt 已在仓库外,首次需生成 |
| | | cd .. && javac -encoding UTF-8 -cp "$(cat talent-card-server/target/cp.txt)" \ |
| | | -d talent-card-server/target/probe-classes .scratch/db-merge/*.java |
| | | java -cp "talent-card-server/target/probe-classes;$(cat talent-card-server/target/cp.txt)" \ |
| | | SchemaDigest "jdbc:mysql://127.0.0.1:8134/talent_card?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&useSSL=false" |
| | | ``` |
| | | |
| | | ## 做法(顺序) |
| | | |
| | | 1. **只读盘点**:`SchemaDigest` 两台各跑一次对比结构;`RowCompare` 逐行比对;`DiffRows` 看具体差异行。 |
| | | 2. **备份**:`SchemaDump` 导出两库的结构与数据到 `backup/`(**该目录被 .gitignore 挡住**:里面有会话令牌、 |
| | | 手机号,绝不入库)。 |
| | | 3. **干跑**:先把要应用的迁移复制到 `dryrun-migrations/`,在本机建的「服务器结构副本」上跑一遍 |
| | | (`FlywayProbe --migrate --no-validate --locations=filesystem:...`),确认不撞列、不依赖被跳过的迁移: |
| | | ```bash |
| | | mkdir -p .scratch/db-merge/dryrun-migrations |
| | | for v in $(seq 127 147); do cp talent-card-server/src/main/resources/db/migration/V${v}__*.sql .scratch/db-merge/dryrun-migrations/; done |
| | | ``` |
| | | 4. **应用迁移**:服务器用 `FlywayProbe --migrate`(只放 V127–V147 的 locations + `--no-validate`,因为 |
| | | V112–V126 仍待应用,全量 locations 会让 V112 撞列失败);本机库 flyway 关着,用 `RunSqlFile` 跑 V147。 |
| | | 5. **数据并集**:`SyncTool` 双向各跑一次(`--dry-run` 先看清单): |
| | | ```bash |
| | | java -cp ... SyncTool <本机url> <服务器url> "--rekey=merchant_operator:10,34,35" |
| | | java -cp ... SyncTool <服务器url> <本机url> |
| | | ``` |
| | | 6. **验收**:`RowCompare` 复核——所有业务表的「仅左/仅右」都应为 0。 |
| | | |
| | | ## 冲突判定规则(重要) |
| | | |
| | | - **只插不改。** 目标库缺的行按原主键插入;主键存在但内容不同的行一律**不覆盖**,只统计。 |
| | | - 两库的同一主键**未必是同一实体**(各自自增、各自新增)。`merchant_operator` 就是这样:本机 #10/#34/#35 |
| | | 是商户 631/632/633 的登录账号,服务器同 id 属于商户 99/90/126。这类**已确认**的撞车才用 |
| | | `--rekey=表:主键,...` 换新主键插入,绝不覆盖对方那条。 |
| | | - **生成列不参与插入**:V132/V134/V135 加了 `generated always as ...`,显式写值会被 MySQL 拒绝。 |
| | | - **自然唯一键冲突交给数据库拒绝**:被拒的行(如 6 行营业时段、2 行协议类型)说明目标库已有同键的行, |
| | | 记录即可,不要绕过去造重复。 |
| | | - **不替人改密码**:`merchant_operator` 有一行的 `password_hash` 两边不同,保持各侧原值。 |
| | | |
| | | ## 复用时的注意事项 |
| | | |
| | | - **两个库会再次分叉。** 只要两边继续各自被写(各自自增 id),下一次仍然需要逐行判读。要长期保持两边 |
| | | 可用,应选一个库作为唯一事实源,另一边定期从它刷新,而不是反复双向合并。 |
| | | - 服务器上 `V112–V126` 仍未应用,且 Flyway 默认 `outOfOrder=false` 会**静默忽略**它们(`info` 显示 |
| | | 「0 条待应用」)。要补必须显式开 `outOfOrder=true`,且那 4 条撞列的迁移要先处理——属于其他业务域。 |
| | | - 服务器库结构上比迁移产物多 28 张历史遗留表(`sys_user`、`payment_record`、`coupon` 等), |
| | | 已确认合并后的代码不再引用任何一张,属死表。 |
| New file |
| | |
| | | import java.sql.Connection; |
| | | import java.sql.DriverManager; |
| | | import java.sql.PreparedStatement; |
| | | import java.sql.ResultSet; |
| | | import java.util.ArrayList; |
| | | import java.util.LinkedHashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.TreeMap; |
| | | |
| | | /** |
| | | * 只读探针:按主键逐行比对两个库的同名表,回答「同一主键在两边是不是同一份内容」。 |
| | | * |
| | | * <p>用法:java RowCompare <左库url> <右库url> [表名,表名...] |
| | | * 默认比对内置的核心业务表清单。不做任何写入。 |
| | | */ |
| | | public class RowCompare { |
| | | |
| | | private static final String[] DEFAULT_TABLES = { |
| | | "merchant", "merchant_store", "merchant_product", "merchant_operator", |
| | | "merchant_onboarding_application", "merchant_onboarding_progress", "merchant_bank_card", |
| | | "merchant_verification_attempt", "merchant_agreement_acceptance", |
| | | "benefit_order", "verify_record", "payment_transaction", "order_refund", |
| | | "payment_reconciliation_issue", "payment_callback_event", |
| | | "talent_user", "talent_card", "talent_dynamic_code", |
| | | "admin_user", "merchant_coupon", "news_article", |
| | | }; |
| | | |
| | | public static void main(String[] args) throws Exception { |
| | | try (Connection left = DriverManager.getConnection(args[0], "root", "123456"); |
| | | Connection right = DriverManager.getConnection(args[1], "root", "123456")) { |
| | | String[] tables = args.length > 2 ? args[2].split(",") : DEFAULT_TABLES; |
| | | System.out.printf("%-34s %7s %7s %7s %7s %7s %7s%n", |
| | | "表", "总数L", "总数R", "同内容", "内容不同", "仅左", "仅右"); |
| | | for (String table : tables) { |
| | | compare(left, right, table.trim()); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private static void compare(Connection left, Connection right, String table) { |
| | | try { |
| | | List<String> keys = primaryKey(left, table); |
| | | if (keys.isEmpty()) { |
| | | System.out.printf("%-34s %7s%n", table, "(无单列主键,跳过)"); |
| | | return; |
| | | } |
| | | String key = keys.get(0); |
| | | // 只比对两边都有的列:本机库可能还没应用某些迁移,列集合不同不代表行内容不同。 |
| | | List<String> leftColumns = columns(left, table); |
| | | List<String> rightColumns = columns(right, table); |
| | | List<String> shared = new ArrayList<>(leftColumns); |
| | | shared.retainAll(rightColumns); |
| | | if (!shared.contains(key)) { |
| | | System.out.printf("%-34s %7s%n", table, "(主键列不在共有列里)"); |
| | | return; |
| | | } |
| | | Map<String, List<String>> leftRows = fingerprint(left, table, key, shared); |
| | | Map<String, List<String>> rightRows = fingerprint(right, table, key, shared); |
| | | int same = 0; |
| | | int different = 0; |
| | | List<String> conflicts = new ArrayList<>(); |
| | | List<String> example = null; |
| | | for (Map.Entry<String, List<String>> entry : leftRows.entrySet()) { |
| | | List<String> other = rightRows.get(entry.getKey()); |
| | | if (other == null) continue; |
| | | if (other.equals(entry.getValue())) same++; |
| | | else { |
| | | different++; |
| | | if (conflicts.size() < 8) conflicts.add(entry.getKey()); |
| | | if (example == null) example = differingColumns(shared, entry.getValue(), other); |
| | | } |
| | | } |
| | | int onlyLeft = 0; |
| | | for (String id : leftRows.keySet()) if (!rightRows.containsKey(id)) onlyLeft++; |
| | | int onlyRight = 0; |
| | | for (String id : rightRows.keySet()) if (!leftRows.containsKey(id)) onlyRight++; |
| | | System.out.printf("%-34s %7d %7d %7d %7d %7d %7d%n", |
| | | table, leftRows.size(), rightRows.size(), same, different, onlyLeft, onlyRight); |
| | | if (!conflicts.isEmpty()) { |
| | | System.out.println(" 主键相同但内容不同:" + String.join(", ", conflicts) |
| | | + (different > conflicts.size() ? " ...(共 " + different + " 条)" : "")); |
| | | if (example != null) System.out.println(" 差异列(示例):" + String.join(", ", example)); |
| | | } |
| | | } catch (Exception exception) { |
| | | System.out.printf("%-34s %7s%n", table, "(" + exception.getMessage() + ")"); |
| | | } |
| | | } |
| | | |
| | | private static List<String> differingColumns(List<String> columns, List<String> left, List<String> right) { |
| | | List<String> differing = new ArrayList<>(); |
| | | for (int index = 0; index < columns.size(); index++) { |
| | | if (!left.get(index).equals(right.get(index))) differing.add(columns.get(index)); |
| | | } |
| | | return differing; |
| | | } |
| | | |
| | | private static List<String> columns(Connection connection, String table) throws Exception { |
| | | List<String> columns = new ArrayList<>(); |
| | | try (PreparedStatement statement = connection.prepareStatement(""" |
| | | select column_name from information_schema.columns |
| | | where table_schema = database() and table_name = ? order by ordinal_position |
| | | """)) { |
| | | statement.setString(1, table); |
| | | try (ResultSet rows = statement.executeQuery()) { |
| | | while (rows.next()) columns.add(rows.getString(1)); |
| | | } |
| | | } |
| | | return columns; |
| | | } |
| | | |
| | | private static List<String> primaryKey(Connection connection, String table) throws Exception { |
| | | List<String> keys = new ArrayList<>(); |
| | | try (PreparedStatement statement = connection.prepareStatement(""" |
| | | select column_name from information_schema.key_column_usage |
| | | where table_schema = database() and table_name = ? and constraint_name = 'PRIMARY' |
| | | order by ordinal_position |
| | | """)) { |
| | | statement.setString(1, table); |
| | | try (ResultSet rows = statement.executeQuery()) { |
| | | while (rows.next()) keys.add(rows.getString(1)); |
| | | } |
| | | } |
| | | return keys; |
| | | } |
| | | |
| | | /** 主键 -> 共有列的内容指纹(按列顺序拼串,null 用特殊标记)。 */ |
| | | private static Map<String, List<String>> fingerprint(Connection connection, String table, String key, |
| | | List<String> columns) throws Exception { |
| | | Map<String, List<String>> rows = new TreeMap<>(); |
| | | String selection = String.join(", ", columns.stream().map(column -> "`" + column + "`").toList()); |
| | | try (PreparedStatement statement = connection.prepareStatement( |
| | | "select " + selection + " from `" + table + "`"); |
| | | ResultSet result = statement.executeQuery()) { |
| | | while (result.next()) { |
| | | List<String> content = new ArrayList<>(columns.size()); |
| | | for (int index = 1; index <= columns.size(); index++) { |
| | | Object value = result.getObject(index); |
| | | content.add(value == null ? "\u0000" : String.valueOf(value)); |
| | | } |
| | | rows.put(String.valueOf(result.getObject(key)), content); |
| | | } |
| | | } |
| | | return rows; |
| | | } |
| | | } |
| New file |
| | |
| | | import java.nio.charset.StandardCharsets; |
| | | import java.nio.file.Files; |
| | | import java.nio.file.Path; |
| | | import java.sql.Connection; |
| | | import java.sql.DriverManager; |
| | | import java.sql.Statement; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * 把一个 .sql 文件按语句逐条执行(备份文件与一次性 DDL 用)。 |
| | | * |
| | | * <p>不处理 DELIMITER:Flyway 自己的迁移文件由 Flyway 执行,这里只跑不含存储过程的脚本。 |
| | | * 用法:java RunSqlFile <jdbc-url> <file.sql> |
| | | */ |
| | | public class RunSqlFile { |
| | | |
| | | public static void main(String[] args) throws Exception { |
| | | String url = args[0]; |
| | | Path file = Path.of(args[1]); |
| | | List<String> statements = split(Files.readString(file, StandardCharsets.UTF_8)); |
| | | int failed = 0; |
| | | try (Connection connection = DriverManager.getConnection(url, "root", "123456")) { |
| | | try (Statement statement = connection.createStatement()) { |
| | | for (String sql : statements) { |
| | | try { |
| | | statement.execute(sql); |
| | | } catch (Exception exception) { |
| | | failed++; |
| | | String head = sql.length() > 120 ? sql.substring(0, 120) + "..." : sql; |
| | | System.out.println("!! 失败:" + exception.getMessage()); |
| | | System.out.println(" " + head.replace('\n', ' ')); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | System.out.println("执行语句 " + statements.size() + " 条,失败 " + failed + " 条"); |
| | | } |
| | | |
| | | /** 按行尾分号切分,并支持 {@code DELIMITER} 指令(迁移里的存储过程需要)。跳过空语句与纯注释块。 */ |
| | | private static List<String> split(String content) { |
| | | List<String> statements = new ArrayList<>(); |
| | | StringBuilder current = new StringBuilder(); |
| | | String delimiter = ";"; |
| | | for (String line : content.split("\n")) { |
| | | String trimmed = line.trim(); |
| | | String upper = trimmed.toUpperCase(java.util.Locale.ROOT); |
| | | if (upper.startsWith("DELIMITER ")) { |
| | | delimiter = trimmed.substring("DELIMITER ".length()).trim(); |
| | | continue; |
| | | } |
| | | if (trimmed.startsWith("--") && current.toString().isBlank()) continue; |
| | | current.append(line).append('\n'); |
| | | if (trimmed.endsWith(delimiter)) { |
| | | String sql = current.toString().trim(); |
| | | String withoutTrailing = sql.substring(0, sql.length() - delimiter.length()).trim(); |
| | | if (!withoutTrailing.isBlank() && !withoutTrailing.startsWith("--")) statements.add(withoutTrailing); |
| | | current.setLength(0); |
| | | } |
| | | } |
| | | return statements; |
| | | } |
| | | } |
| New file |
| | |
| | | import java.sql.Connection; |
| | | import java.sql.DriverManager; |
| | | import java.sql.PreparedStatement; |
| | | import java.sql.ResultSet; |
| | | import java.sql.SQLException; |
| | | import java.sql.Statement; |
| | | |
| | | /** |
| | | * 只读探针:把一个库的结构摘要打到标准输出,用于合并前比对目标库与本机开发库。 |
| | | * |
| | | * <p>不含任何写入语句。用法:java SchemaDigest <jdbc-url> |
| | | */ |
| | | public class SchemaDigest { |
| | | |
| | | public static void main(String[] args) throws Exception { |
| | | String url = args[0]; |
| | | try (Connection connection = DriverManager.getConnection(url, "root", "123456")) { |
| | | String database = connection.getCatalog(); |
| | | System.out.println("== SERVER =="); |
| | | try (Statement statement = connection.createStatement(); |
| | | ResultSet rows = statement.executeQuery("select version()")) { |
| | | rows.next(); |
| | | System.out.println(" " + rows.getString(1)); |
| | | } |
| | | System.out.println("== DATABASE " + database + " =="); |
| | | |
| | | System.out.println("== FLYWAY =="); |
| | | try (Statement statement = connection.createStatement(); |
| | | ResultSet rows = statement.executeQuery( |
| | | "select version, description, success from flyway_schema_history order by installed_rank")) { |
| | | while (rows.next()) { |
| | | System.out.println(" " + rows.getString(1) + " | " + rows.getString(2) |
| | | + " | success=" + rows.getBoolean(3)); |
| | | } |
| | | } catch (SQLException exception) { |
| | | System.out.println(" (没有 flyway_schema_history:" + exception.getMessage() + ")"); |
| | | } |
| | | |
| | | System.out.println("== TABLES =="); |
| | | try (PreparedStatement statement = connection.prepareStatement(""" |
| | | select table_name, table_rows, table_comment from information_schema.tables |
| | | where table_schema = ? order by table_name |
| | | """)) { |
| | | statement.setString(1, database); |
| | | try (ResultSet rows = statement.executeQuery()) { |
| | | while (rows.next()) { |
| | | System.out.println(" " + rows.getString(1) + " rows~" + rows.getLong(2) |
| | | + " [" + rows.getString(3) + "]"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | System.out.println("== COLUMNS =="); |
| | | try (PreparedStatement statement = connection.prepareStatement(""" |
| | | select table_name, column_name, column_type, is_nullable, coalesce(column_default, '') |
| | | from information_schema.columns where table_schema = ? |
| | | order by table_name, ordinal_position |
| | | """)) { |
| | | statement.setString(1, database); |
| | | try (ResultSet rows = statement.executeQuery()) { |
| | | while (rows.next()) { |
| | | System.out.println(" " + rows.getString(1) + "." + rows.getString(2) |
| | | + " " + rows.getString(3) + " null=" + rows.getString(4) |
| | | + " default=" + rows.getString(5)); |
| | | } |
| | | } |
| | | } |
| | | |
| | | System.out.println("== INDEXES =="); |
| | | try (PreparedStatement statement = connection.prepareStatement(""" |
| | | select table_name, index_name, non_unique, seq_in_index, column_name |
| | | from information_schema.statistics where table_schema = ? |
| | | order by table_name, index_name, seq_in_index |
| | | """)) { |
| | | statement.setString(1, database); |
| | | try (ResultSet rows = statement.executeQuery()) { |
| | | while (rows.next()) { |
| | | System.out.println(" " + rows.getString(1) + " " + rows.getString(2) |
| | | + " unique=" + (rows.getInt(3) == 0) + " seq=" + rows.getInt(4) |
| | | + " col=" + rows.getString(5)); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| New file |
| | |
| | | import java.sql.Connection; |
| | | import java.sql.DriverManager; |
| | | import java.sql.PreparedStatement; |
| | | import java.sql.ResultSet; |
| | | import java.sql.Statement; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | import java.util.StringJoiner; |
| | | |
| | | /** |
| | | * 只读探针:导出某个库的结构(SHOW CREATE TABLE)或指定表的数据(INSERT),用于迁移前备份。 |
| | | * |
| | | * <p>用法: |
| | | * <pre> |
| | | * java SchemaDump <jdbc-url> # 全部表的结构 |
| | | * java SchemaDump <jdbc-url> --data=t1,t2 # 指定表的数据 |
| | | * </pre> |
| | | */ |
| | | public class SchemaDump { |
| | | |
| | | public static void main(String[] args) throws Exception { |
| | | String url = args[0]; |
| | | String dataTables = null; |
| | | for (String arg : args) { |
| | | if (arg.startsWith("--data=")) dataTables = arg.substring("--data=".length()); |
| | | } |
| | | try (Connection connection = DriverManager.getConnection(url, "root", "123456")) { |
| | | if (dataTables == null) { |
| | | dumpSchema(connection); |
| | | } else { |
| | | for (String table : dataTables.split(",")) { |
| | | dumpData(connection, table.trim()); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | private static void dumpSchema(Connection connection) throws Exception { |
| | | System.out.println("-- 结构备份:" + connection.getCatalog() + ",导出时间 " + java.time.LocalDateTime.now()); |
| | | System.out.println("-- 还原方式:在空库里按顺序执行本文件(表按名称排序,先建表后加外键由 MySQL 自行处理)。"); |
| | | System.out.println("SET FOREIGN_KEY_CHECKS = 0;"); |
| | | for (String table : tables(connection)) { |
| | | try (Statement statement = connection.createStatement(); |
| | | ResultSet rows = statement.executeQuery("show create table `" + table + "`")) { |
| | | rows.next(); |
| | | System.out.println(); |
| | | System.out.println("-- " + table); |
| | | System.out.println("DROP TABLE IF EXISTS `" + table + "`;"); |
| | | System.out.println(rows.getString(2) + ";"); |
| | | } |
| | | } |
| | | System.out.println(); |
| | | System.out.println("SET FOREIGN_KEY_CHECKS = 1;"); |
| | | } |
| | | |
| | | private static void dumpData(Connection connection, String table) throws Exception { |
| | | System.out.println(); |
| | | System.out.println("-- 数据备份 " + table + "(导出时间 " + java.time.LocalDateTime.now() + ")"); |
| | | try (Statement statement = connection.createStatement(); |
| | | ResultSet rows = statement.executeQuery("select * from `" + table + "`")) { |
| | | int columns = rows.getMetaData().getColumnCount(); |
| | | List<String> names = new ArrayList<>(); |
| | | for (int index = 1; index <= columns; index++) names.add(rows.getMetaData().getColumnLabel(index)); |
| | | int count = 0; |
| | | while (rows.next()) { |
| | | StringJoiner values = new StringJoiner(", "); |
| | | for (int index = 1; index <= columns; index++) { |
| | | values.add(literal(rows.getObject(index))); |
| | | } |
| | | System.out.println("INSERT INTO `" + table + "` (`" + String.join("`, `", names) + "`) VALUES (" |
| | | + values + ");"); |
| | | count++; |
| | | } |
| | | System.out.println("-- " + table + " 共 " + count + " 行"); |
| | | } |
| | | } |
| | | |
| | | private static List<String> tables(Connection connection) throws Exception { |
| | | List<String> tables = new ArrayList<>(); |
| | | try (PreparedStatement statement = connection.prepareStatement(""" |
| | | select table_name from information_schema.tables |
| | | where table_schema = ? and table_type = 'BASE TABLE' order by table_name |
| | | """)) { |
| | | statement.setString(1, connection.getCatalog()); |
| | | try (ResultSet rows = statement.executeQuery()) { |
| | | while (rows.next()) tables.add(rows.getString(1)); |
| | | } |
| | | } |
| | | return tables; |
| | | } |
| | | |
| | | /** Java 17 已经移除 javax.xml.bind,自带一个十六进制编码。 */ |
| | | private static String hex(byte[] bytes) { |
| | | StringBuilder text = new StringBuilder(bytes.length * 2); |
| | | for (byte value : bytes) text.append(String.format("%02X", value)); |
| | | return text.toString(); |
| | | } |
| | | |
| | | /** 一个够用的字面量转义:NULL、数字裸写、其余加引号并转义控制字符。 */ |
| | | private static String literal(Object value) { |
| | | if (value == null) return "NULL"; |
| | | if (value instanceof Number || value instanceof Boolean) return String.valueOf(value); |
| | | if (value instanceof byte[] bytes) return "0x" + hex(bytes); |
| | | String text = String.valueOf(value); |
| | | StringBuilder escaped = new StringBuilder("'"); |
| | | for (char character : text.toCharArray()) { |
| | | switch (character) { |
| | | case '\'' -> escaped.append("''"); |
| | | case '\\' -> escaped.append("\\\\"); |
| | | case '\n' -> escaped.append("\\n"); |
| | | case '\r' -> escaped.append("\\r"); |
| | | case '\0' -> escaped.append("\\0"); |
| | | case '\u001a' -> escaped.append("\\Z"); |
| | | default -> escaped.append(character); |
| | | } |
| | | } |
| | | return escaped.append("'").toString(); |
| | | } |
| | | } |
| New file |
| | |
| | | import java.sql.Connection; |
| | | import java.sql.DriverManager; |
| | | import java.sql.PreparedStatement; |
| | | import java.sql.ResultSet; |
| | | import java.sql.ResultSetMetaData; |
| | | import java.sql.Types; |
| | | import java.util.ArrayList; |
| | | import java.util.LinkedHashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.TreeMap; |
| | | |
| | | /** |
| | | * 两个库按主键做并集:目标库缺的行插入,同主键内容不同的行按「较新者胜」更新。 |
| | | * |
| | | * <p>用法:java SyncTool <源url> <目标url> [--dry-run] |
| | | * |
| | | * <p>只处理两边都存在的业务表;会话、审计、动态码、事件这类瞬时表与仅存在于一侧的遗留表都不动。 |
| | | * 全部使用参数化语句,不拼字符串,避免转义问题。 |
| | | */ |
| | | public class SyncTool { |
| | | |
| | | /** 不参与合并的表:瞬时状态、审计流水、固定参考数据与迁移账本。 */ |
| | | private static final List<String> EXCLUDED_SUFFIXES = List.of( |
| | | "_session", "_audit", "_event", "_log", "_dynamic_code", "_verification_code", |
| | | "bank_branch_directory", "flyway_schema_history", "merchant_verification_attempt", |
| | | "merchant_login_audit", "admin_login_audit", "talent_dynamic_code", |
| | | "order_dynamic_verification_code", "free_stay_verification_code"); |
| | | |
| | | public static void main(String[] args) throws Exception { |
| | | String sourceUrl = args[0]; |
| | | String targetUrl = args[1]; |
| | | boolean dryRun = false; |
| | | java.util.Map<String, java.util.Set<String>> rekey = new java.util.HashMap<>(); |
| | | for (String arg : args) { |
| | | if ("--dry-run".equals(arg)) dryRun = true; |
| | | // --rekey=表:主键,主键 —— 只对这些「已确认同主键不同实体」的行换新主键插入。 |
| | | if (arg.startsWith("--rekey=")) { |
| | | String[] parts = arg.substring("--rekey=".length()).split(":"); |
| | | java.util.Set<String> ids = new java.util.HashSet<>(); |
| | | for (String id : parts[1].split(",")) ids.add(id.trim()); |
| | | rekey.put(parts[0].trim(), ids); |
| | | } |
| | | } |
| | | |
| | | try (Connection source = DriverManager.getConnection(sourceUrl, "root", "123456"); |
| | | Connection target = DriverManager.getConnection(targetUrl, "root", "123456")) { |
| | | List<String> tables = sharedTables(source, target); |
| | | int totalInserted = 0; |
| | | int totalConflicts = 0; |
| | | int totalSkipped = 0; |
| | | System.out.printf("%-38s %8s %9s %8s%n", "表", "插入", "冲突未动", "插入失败"); |
| | | for (String table : tables) { |
| | | if (excluded(table)) continue; |
| | | String key = primaryKey(source, table); |
| | | if (key == null) continue; |
| | | List<String> columns = sharedColumns(source, target, table); |
| | | if (columns == null || columns.isEmpty() || !columns.contains(key)) continue; |
| | | int[] result = sync(source, target, table, key, columns, dryRun, rekey.get(table)); |
| | | if (result[0] != 0 || result[1] != 0 || result[2] != 0) { |
| | | System.out.printf("%-38s %8d %9d %8d%n", table, result[0], result[1], result[2]); |
| | | } |
| | | totalInserted += result[0]; |
| | | totalConflicts += result[1]; |
| | | totalSkipped += result[2]; |
| | | } |
| | | System.out.println("合计:插入 " + totalInserted + " 行,冲突未动 " + totalConflicts |
| | | + " 行,插入失败 " + totalSkipped + " 行" + (dryRun ? "(干跑,未写入)" : "(已写入)")); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 只做「并集插入」:目标库缺的行按原主键插入;主键存在但内容不同的行一律不覆盖(只计数)。 |
| | | * |
| | | * <p>冲突行不动是有意的:两个库的同一主键未必是同一实体(各自的登录账号、卡、进件记录会各自增长), |
| | | * 覆盖任何一侧都会改坏那侧的数据。{@code rekey} 列表里的表是已确认「同主键不同实体」的, |
| | | * 这类行改用目标库的新主键插入,避免丢掉源侧那条真实存在的数据。 |
| | | */ |
| | | private static int[] sync(Connection source, Connection target, String table, String key, |
| | | List<String> columns, boolean dryRun, java.util.Set<String> rekeyIds) throws Exception { |
| | | Map<String, Object[]> sourceRows = rows(source, table, key, columns); |
| | | Map<String, Object[]> targetRows = rows(target, table, key, columns); |
| | | String columnList = String.join(", ", columns.stream().map(c -> "`" + c + "`").toList()); |
| | | String placeholders = String.join(", ", columns.stream().map(c -> "?").toList()); |
| | | int keyIndex = columns.indexOf(key); |
| | | long nextId = -1; |
| | | int inserted = 0; |
| | | int conflicts = 0; |
| | | int failed = 0; |
| | | for (Map.Entry<String, Object[]> entry : sourceRows.entrySet()) { |
| | | Object[] targetRow = targetRows.get(entry.getKey()); |
| | | Object[] values = entry.getValue(); |
| | | String insertId = entry.getKey(); |
| | | if (targetRow != null) { |
| | | if (sameRow(values, targetRow)) continue; |
| | | if (rekeyIds == null || !rekeyIds.contains(entry.getKey())) { |
| | | conflicts++; |
| | | continue; |
| | | } |
| | | // 同主键不同实体:换一个新主键插入,别覆盖目标库那条。只在真要换号时才取 max, |
| | | // 免得在字符串主键(例如 talent_user_agreement)上做数字解析。 |
| | | if (nextId < 0) nextId = maxId(target, table, key) + 1; |
| | | insertId = String.valueOf(nextId); |
| | | values = values.clone(); |
| | | values[keyIndex] = nextId; |
| | | nextId++; |
| | | } |
| | | if (dryRun) { |
| | | inserted++; |
| | | continue; |
| | | } |
| | | try (PreparedStatement statement = target.prepareStatement( |
| | | "insert into `" + table + "` (" + columnList + ") values (" + placeholders + ")")) { |
| | | bind(statement, values, columns); |
| | | statement.executeUpdate(); |
| | | inserted++; |
| | | } catch (Exception exception) { |
| | | failed++; |
| | | System.out.println(" ! " + table + " 主键 " + insertId + " 插入失败:" + exception.getMessage()); |
| | | } |
| | | } |
| | | return new int[]{inserted, conflicts, failed}; |
| | | } |
| | | |
| | | private static long maxId(Connection connection, String table, String key) throws Exception { |
| | | try (PreparedStatement statement = connection.prepareStatement( |
| | | "select coalesce(max(`" + key + "`), 0) from `" + table + "`"); |
| | | ResultSet rows = statement.executeQuery()) { |
| | | rows.next(); |
| | | return rows.getLong(1); |
| | | } |
| | | } |
| | | |
| | | private static boolean sameRow(Object[] source, Object[] target) { |
| | | if (source.length != target.length) return false; |
| | | for (int index = 0; index < source.length; index++) { |
| | | String left = source[index] == null ? "\u0000" : String.valueOf(source[index]); |
| | | String right = target[index] == null ? "\u0000" : String.valueOf(target[index]); |
| | | if (!left.equals(right)) return false; |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | private static Map<String, Object[]> rows(Connection connection, String table, String key, |
| | | List<String> columns) throws Exception { |
| | | Map<String, Object[]> rows = new TreeMap<>(); |
| | | String selection = String.join(", ", columns.stream().map(c -> "`" + c + "`").toList()); |
| | | try (PreparedStatement statement = connection.prepareStatement( |
| | | "select " + selection + " from `" + table + "`"); |
| | | ResultSet result = statement.executeQuery()) { |
| | | while (result.next()) { |
| | | Object[] values = new Object[columns.size()]; |
| | | for (int index = 0; index < columns.size(); index++) values[index] = result.getObject(index + 1); |
| | | rows.put(String.valueOf(result.getObject(key)), values); |
| | | } |
| | | } |
| | | return rows; |
| | | } |
| | | |
| | | private static void bind(PreparedStatement statement, Object[] values, List<String> columns) throws Exception { |
| | | for (int index = 0; index < values.length; index++) { |
| | | if (values[index] == null) statement.setNull(index + 1, Types.NULL); |
| | | else statement.setObject(index + 1, values[index]); |
| | | } |
| | | } |
| | | |
| | | private static boolean excluded(String table) { |
| | | for (String suffix : EXCLUDED_SUFFIXES) if (table.equals(suffix) || table.endsWith(suffix)) return true; |
| | | return false; |
| | | } |
| | | |
| | | private static List<String> sharedTables(Connection source, Connection target) throws Exception { |
| | | List<String> sourceTables = tables(source); |
| | | List<String> targetTables = tables(target); |
| | | sourceTables.retainAll(targetTables); |
| | | return sourceTables; |
| | | } |
| | | |
| | | private static List<String> tables(Connection connection) throws Exception { |
| | | List<String> tables = new ArrayList<>(); |
| | | try (PreparedStatement statement = connection.prepareStatement(""" |
| | | select table_name from information_schema.tables |
| | | where table_schema = database() and table_type = 'BASE TABLE' order by table_name |
| | | """); |
| | | ResultSet rows = statement.executeQuery()) { |
| | | while (rows.next()) tables.add(rows.getString(1)); |
| | | } |
| | | return tables; |
| | | } |
| | | |
| | | private static List<String> sharedColumns(Connection source, Connection target, String table) throws Exception { |
| | | List<String> columns = columns(source, table); |
| | | columns.retainAll(columns(target, table)); |
| | | return columns; |
| | | } |
| | | |
| | | /** |
| | | * 可写列:跳过生成列({@code generated always as ...})。生成列由数据库按表达式算出来, |
| | | * 显式写入会被 MySQL 拒绝(V132/V134/V135 都加了生成列)。 |
| | | */ |
| | | private static List<String> columns(Connection connection, String table) throws Exception { |
| | | List<String> columns = new ArrayList<>(); |
| | | try (PreparedStatement statement = connection.prepareStatement(""" |
| | | select column_name, extra, generation_expression from information_schema.columns |
| | | where table_schema = database() and table_name = ? order by ordinal_position |
| | | """)) { |
| | | statement.setString(1, table); |
| | | try (ResultSet rows = statement.executeQuery()) { |
| | | while (rows.next()) { |
| | | String extra = rows.getString(2) == null ? "" : rows.getString(2).toUpperCase(java.util.Locale.ROOT); |
| | | String expression = rows.getString(3); |
| | | boolean generated = extra.contains("GENERATED") |
| | | || (expression != null && !expression.isBlank()); |
| | | if (!generated) columns.add(rows.getString(1)); |
| | | } |
| | | } |
| | | } |
| | | return columns; |
| | | } |
| | | |
| | | private static String primaryKey(Connection connection, String table) throws Exception { |
| | | List<String> keys = new ArrayList<>(); |
| | | try (PreparedStatement statement = connection.prepareStatement(""" |
| | | select column_name from information_schema.key_column_usage |
| | | where table_schema = database() and table_name = ? and constraint_name = 'PRIMARY' |
| | | order by ordinal_position |
| | | """)) { |
| | | statement.setString(1, table); |
| | | try (ResultSet rows = statement.executeQuery()) { |
| | | while (rows.next()) keys.add(rows.getString(1)); |
| | | } |
| | | } |
| | | return keys.size() == 1 ? keys.get(0) : null; |
| | | } |
| | | } |
| New file |
| | |
| | | delete from flyway_schema_history; |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (1, '1', '<< Flyway Baseline >>', 'BASELINE', '<< Flyway Baseline >>', NULL, 'root', '2026-07-17 15:11:02.0', 0, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (2, '2', 'base business tables', 'SQL', 'V2__base_business_tables.sql', -2043420698, 'root', '2026-07-17 15:34:42.0', 51, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (3, '3', 'merchant admin fields', 'SQL', 'V3__merchant_admin_fields.sql', 207505230, 'root', '2026-07-20 11:21:55.0', 34, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (4, '4', 'merchant coupon tables', 'SQL', 'V4__merchant_coupon_tables.sql', 1321273322, 'root', '2026-07-23 14:17:45.0', 32, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (5, '5', 'merchant product form config', 'SQL', 'V5__merchant_product_form_config.sql', -1898050533, 'root', '2026-07-23 15:04:21.0', 144, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (6, '6', 'order refund records', 'SQL', 'V6__order_refund_records.sql', -1905488592, 'root', '2026-07-23 17:18:47.0', 24, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (7, '7', 'service applications', 'SQL', 'V7__service_applications.sql', -862055421, 'root', '2026-07-23 17:49:47.0', 36, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (8, '8', 'card applications', 'SQL', 'V8__card_applications.sql', 1949570785, 'root', '2026-07-24 11:26:02.0', 41, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (9, '9', 'operation management', 'SQL', 'V9__operation_management.sql', 553221548, 'root', '2026-07-24 15:31:18.0', 41, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (10, '10', 'news articles', 'SQL', 'V10__news_articles.sql', -1923086938, 'root', '2026-07-24 15:31:18.0', 10, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (11, '11', 'seed demo news articles', 'SQL', 'V11__seed_demo_news_articles.sql', 1961096501, 'root', '2026-07-24 15:48:12.0', 10, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (12, '12', 'seed demo merchants and products', 'SQL', 'V12__seed_demo_merchants_and_products.sql', -1650493658, 'root', '2026-07-24 16:21:40.0', 19, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (13, '13', 'seed demo hotpot product', 'SQL', 'V13__seed_demo_hotpot_product.sql', -1195203486, 'root', '2026-07-24 16:24:21.0', 7, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (14, '14', 'backfill demo product images', 'SQL', 'V14__backfill_demo_product_images.sql', -1005819135, 'root', '2026-07-24 18:04:19.0', 13, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (15, '15', 'food topic configuration', 'SQL', 'V15__food_topic_configuration.sql', 31999599, 'root', '2026-07-27 14:13:18.0', 74, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (16, '16', 'merchant detail configuration', 'SQL', 'V16__merchant_detail_configuration.sql', -2004483606, 'root', '2026-07-27 15:40:03.0', 262, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (17, '17', 'seed default food merchant product', 'SQL', 'V17__seed_default_food_merchant_product.sql', 687180813, 'root', '2026-07-27 15:41:42.0', 13, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (18, '18', 'backfill default food product detail', 'SQL', 'V18__backfill_default_food_product_detail.sql', 1212055854, 'root', '2026-07-27 16:22:45.0', 5, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (19, '19', 'seed default food coupon', 'SQL', 'V19__seed_default_food_coupon.sql', 513640743, 'root', '2026-07-27 17:04:06.0', 10, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (20, '20', 'talent card dynamic codes', 'SQL', 'V20__talent_card_dynamic_codes.sql', 831760405, 'root', '2026-07-28 10:40:19.0', 26, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (21, '21', 'seed talent policies', 'SQL', 'V21__seed_talent_policies.sql', -552329513, 'root', '2026-07-28 11:33:32.0', 13, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (22, '22', 'policy detail content configuration', 'SQL', 'V22__policy_detail_content_configuration.sql', 1737648695, 'root', '2026-07-28 14:02:34.0', 136, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (23, '23', 'card upgrade honors', 'SQL', 'V23__card_upgrade_honors.sql', 1211789682, 'root', '2026-07-28 14:35:11.0', 113, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (24, '24', 'seed usage records', 'SQL', 'V24__seed_usage_records.sql', 418900967, 'root', '2026-07-28 15:09:09.0', 10, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (25, '25', 'pending order snapshots', 'SQL', 'V25__pending_order_snapshots.sql', -2138610660, 'root', '2026-07-28 15:19:48.0', 786, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (26, '26', 'align pending order coupon product', 'SQL', 'V26__align_pending_order_coupon_product.sql', -2125754310, 'root', '2026-07-28 15:22:40.0', 8, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (27, '27', 'order dynamic verification codes', 'SQL', 'V27__order_dynamic_verification_codes.sql', -838067477, 'root', '2026-07-28 15:32:02.0', 17, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (28, '28', 'order product cover snapshots', 'SQL', 'V28__order_product_cover_snapshots.sql', -918944819, 'root', '2026-07-28 15:37:40.0', 65, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (29, '29', 'service application processing snapshots', 'SQL', 'V29__service_application_processing_snapshots.sql', -574763565, 'root', '2026-07-28 15:58:04.0', 275, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (30, '30', 'enable demo family cards', 'SQL', 'V30__enable_demo_family_cards.sql', 8653234, 'root', '2026-07-28 16:16:24.0', 6, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (31, '31', 'expand demo family card limit', 'SQL', 'V31__expand_demo_family_card_limit.sql', 1776100093, 'root', '2026-07-28 16:17:47.0', 7, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (32, '32', 'align demo family card level', 'SQL', 'V32__align_demo_family_card_level.sql', -280029008, 'root', '2026-07-28 16:56:41.0', 5, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (33, '33', 'agreement and session revocation', 'SQL', 'V33__agreement_and_session_revocation.sql', 1950064719, 'root', '2026-07-28 17:05:57.0', 32, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (34, '34', 'agreement valid until', 'SQL', 'V34__agreement_valid_until.sql', -1431323798, 'root', '2026-07-28 17:09:09.0', 74, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (35, '35', 'travel topic configuration', 'SQL', 'V35__travel_topic_configuration.sql', 959061645, 'root', '2026-07-28 17:21:18.0', 14, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (36, '36', 'expand demo travel merchants', 'SQL', 'V36__expand_demo_travel_merchants.sql', -1960951959, 'root', '2026-07-28 17:22:55.0', 8, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (37, '37', 'stay topic configuration', 'SQL', 'V37__stay_topic_configuration.sql', 1865939486, 'root', '2026-07-28 17:30:39.0', 19, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (38, '38', 'entertainment topic configuration', 'SQL', 'V38__entertainment_topic_configuration.sql', -2111904807, 'root', '2026-07-28 17:55:43.0', 15, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (39, '39', 'cinema coupon claims', 'SQL', 'V39__cinema_coupon_claims.sql', 1400383867, 'root', '2026-07-28 18:05:00.0', 40, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (40, '40', 'cinema coupon exchange codes', 'SQL', 'V40__cinema_coupon_exchange_codes.sql', -1179843036, 'root', '2026-07-28 18:15:47.0', 304, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (41, '41', 'backfill legacy movie ticket claim', 'SQL', 'V41__backfill_legacy_movie_ticket_claim.sql', 794314898, 'root', '2026-07-28 18:24:42.0', 9, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (42, '42', 'transport topic configuration', 'SQL', 'V42__transport_topic_configuration.sql', -529838104, 'root', '2026-07-29 10:05:30.0', 21, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (43, '43', 'fuel merchant detail configuration', 'SQL', 'V43__fuel_merchant_detail_configuration.sql', -193373451, 'root', '2026-07-29 11:12:27.0', 74, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (44, '44', 'parking merchant detail configuration', 'SQL', 'V44__parking_merchant_detail_configuration.sql', 153231323, 'root', '2026-07-29 11:50:21.0', 55, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (45, '45', 'car wash merchant detail configuration', 'SQL', 'V45__car_wash_merchant_detail_configuration.sql', 1243986746, 'root', '2026-07-29 15:43:09.0', 42, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (46, '46', 'shopping topic configuration', 'SQL', 'V46__shopping_topic_configuration.sql', -405757661, 'root', '2026-07-29 15:56:19.0', 58, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (47, '47', 'shopping service detail configuration', 'SQL', 'V47__shopping_service_detail_configuration.sql', 583084764, 'root', '2026-07-29 16:03:00.0', 20, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (48, '48', 'premium topic configuration', 'SQL', 'V48__premium_topic_configuration.sql', 1808187478, 'root', '2026-07-29 16:10:21.0', 58, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (49, '49', 'premium service coordinates', 'SQL', 'V49__premium_service_coordinates.sql', -856027090, 'root', '2026-07-29 16:11:38.0', 7, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (50, '50', 'spouse employment benefit configuration', 'SQL', 'V50__spouse_employment_benefit_configuration.sql', 100496994, 'root', '2026-07-29 16:20:51.0', 142, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (51, '51', 'expand spouse sensitive fields', 'SQL', 'V51__expand_spouse_sensitive_fields.sql', 371101169, 'root', '2026-07-29 16:26:13.0', 58, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (52, '52', 'medical package configuration', 'SQL', 'V52__medical_package_configuration.sql', 1445312728, 'root', '2026-07-29 16:37:30.0', 34, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (53, '53', 'admin approval benefit configuration', 'SQL', 'V53__admin_approval_benefit_configuration.sql', -501806046, 'root', '2026-07-29 17:00:57.0', 43, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (54, '54', 'finance service detail configuration', 'SQL', 'V54__finance_service_detail_configuration.sql', -1203626545, 'root', '2026-07-29 17:09:10.0', 16, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (55, '55', 'children entrustment benefit configuration', 'SQL', 'V55__children_entrustment_benefit_configuration.sql', 562821011, 'root', '2026-07-29 17:21:44.0', 32, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (56, '56', 'children information', 'SQL', 'V56__children_information.sql', -606900830, 'root', '2026-07-29 17:29:47.0', 20, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (57, '57', 'talent dynamic code context', 'SQL', 'V57__talent_dynamic_code_context.sql', 252711807, 'root', '2026-07-29 17:41:47.0', 181, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (58, '58', 'merchant operator authentication', 'SQL', 'V58__merchant_operator_authentication.sql', 1749070877, 'root', '2026-07-29 20:34:00.0', 104, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (59, '59', 'merchant dashboard and verification attempts', 'SQL', 'V59__merchant_dashboard_and_verification_attempts.sql', 526735355, 'root', '2026-07-29 21:24:24.0', 28, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (60, '60', 'merchant management configuration', 'SQL', 'V60__merchant_management_configuration.sql', 204934765, 'root', '2026-07-30 14:42:08.0', 48, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (61, '61', 'huifu payment transactions', 'SQL', 'V61__huifu_payment_transactions.sql', -472346255, 'root', '2026-07-30 16:42:05.0', 58, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (62, '62', 'talent wechat sessions', 'SQL', 'V62__talent_wechat_sessions.sql', 1469730593, 'root', '2026-07-30 16:49:14.0', 26, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (63, '63', 'payment retry attempts', 'SQL', 'V63__payment_retry_attempts.sql', 787341541, 'root', '2026-07-31 10:14:44.0', 138, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (64, '64', 'backfill pending order expiry', 'SQL', 'V64__backfill_pending_order_expiry.sql', -1164474871, 'root', '2026-07-31 10:31:19.0', 10, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (65, '65', 'order create idempotency', 'SQL', 'V65__order_create_idempotency.sql', 1411270481, 'root', '2026-07-31 11:50:53.0', 145, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (66, '66', 'huifu refund transactions', 'SQL', 'V66__huifu_refund_transactions.sql', 1267247047, 'root', '2026-07-31 14:19:25.0', 543, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (67, '67', 'merchant verification reversal', 'SQL', 'V67__merchant_verification_reversal.sql', 334204971, 'root', '2026-07-31 15:38:24.0', 127, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (68, '68', 'merchant verification idempotency', 'SQL', 'V68__merchant_verification_idempotency.sql', 191823811, 'root', '2026-07-31 15:38:24.0', 36, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (69, '69', 'children entrustment school details', 'SQL', 'V69__children_entrustment_school_details.sql', 1910003241, 'root', '2026-07-31 15:38:24.0', 87, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (70, '70', 'merchant verification revoke idempotency', 'SQL', 'V70__merchant_verification_revoke_idempotency.sql', -1024625823, 'root', '2026-07-31 15:38:24.0', 28, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (71, '71', 'merchant multi credential verification', 'SQL', 'V71__merchant_multi_credential_verification.sql', 388538953, 'root', '2026-07-31 15:38:24.0', 120, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (72, '72', 'merchant manual consumption orders', 'SQL', 'V72__merchant_manual_consumption_orders.sql', -22824883, 'root', '2026-07-31 16:41:36.0', 193, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (73, '73', 'seed merchant manual consumption demo rule', 'SQL', 'V73__seed_merchant_manual_consumption_demo_rule.sql', 770596653, 'root', '2026-07-31 16:41:36.0', 4, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (74, '74', 'migrate legacy equity image categories', 'SQL', 'V74__migrate_legacy_equity_image_categories.sql', 1858492956, 'root', '2026-07-31 17:56:53.0', 16, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (75, '75', 'retire seeded demo merchants', 'SQL', 'V75__retire_seeded_demo_merchants.sql', 1073699067, 'root', '2026-07-31 18:13:30.0', 9, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (76, '76', 'admin operator authentication', 'SQL', 'V76__admin_operator_authentication.sql', -1107934867, 'root', '2026-07-31 18:23:36.0', 50, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (77, '77', 'talent advisor assignment', 'SQL', 'V77__talent_advisor_assignment.sql', 620357384, 'root', '2026-08-01 17:44:13.0', 132, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (78, '78', 'admin management configuration', 'SQL', 'V78__admin_management_configuration.sql', -788761022, 'root', '2026-08-01 19:36:57.0', 36, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (79, '79', 'repair food merchant text encoding', 'SQL', 'V79__repair_food_merchant_text_encoding.sql', 1196348806, 'root', '2026-08-01 20:09:49.0', 8, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (80, '80', 'merchant settlement workflow', 'SQL', 'V80__merchant_settlement_workflow.sql', 1716776309, 'root', '2026-08-03 10:13:52.0', 71, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (81, '81', 'payment reconciliation', 'SQL', 'V81__payment_reconciliation.sql', 2058647688, 'root', '2026-08-03 10:13:52.0', 18, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (82, '82', 'admin role permissions', 'SQL', 'V82__admin_role_permissions.sql', -1120804392, 'root', '2026-08-03 14:44:48.0', 81, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (83, '83', 'admin operator profile fields', 'SQL', 'V83__admin_operator_profile_fields.sql', -1543562906, 'root', '2026-08-03 14:44:48.0', 215, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (84, '84', 'huifu withdrawal binding', 'SQL', 'V84__huifu_withdrawal_binding.sql', -819423056, 'root', '2026-08-03 14:44:49.0', 85, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (85, '85', 'merchant rights configuration', 'SQL', 'V85__merchant_rights_configuration.sql', 1257240909, 'root', '2026-08-03 16:14:05.0', 119, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (86, '86', 'rename standard talent card to elite', 'SQL', 'V86__rename_standard_talent_card_to_elite.sql', -949505761, 'root', '2026-08-03 16:14:05.0', 7, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (87, '87', 'parking plate registration phase2', 'SQL', 'V87__parking_plate_registration_phase2.sql', 2033817652, 'root', '2026-08-04 18:35:28.0', 174, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (88, '88', 'ticket package code pool', 'SQL', 'V88__ticket_package_code_pool.sql', 352881850, 'root', '2026-08-04 18:35:28.0', 40, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (89, '89', 'merchant display policy events', 'SQL', 'V89__merchant_display_policy_events.sql', -343153799, 'root', '2026-08-04 18:35:28.0', 13, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (90, '90', 'dependent card apply status log', 'SQL', 'V90__dependent_card_apply_status_log.sql', -951264615, 'root', '2026-08-04 18:35:28.0', 12, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (91, '91', 'service application unified appointments', 'SQL', 'V91__service_application_unified_appointments.sql', -2058908979, 'root', '2026-08-04 18:35:29.0', 836, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (92, '92', 'admin approval organization extra info', 'SQL', 'V92__admin_approval_organization_extra_info.sql', -1835237241, 'root', '2026-08-04 18:40:33.0', 17, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (93, '93', 'merchant coupon distribution management', 'SQL', 'V93__merchant_coupon_distribution_management.sql', 357720156, 'root', '2026-08-06 16:14:09.0', 269, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (94, '94', 'service application operation log', 'SQL', 'V94__service_application_operation_log.sql', -1131973588, 'root', '2026-08-06 16:14:09.0', 38, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (95, '95', 'car wash credential audit', 'SQL', 'V95__car_wash_credential_audit.sql', -1720962674, 'root', '2026-08-06 16:14:09.0', 140, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (96, '96', 'parking plate operation log', 'SQL', 'V96__parking_plate_operation_log.sql', -775124057, 'root', '2026-08-06 16:14:09.0', 50, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (97, '98', 'merchant coupon talent level quantities', 'SQL', 'V98__merchant_coupon_talent_level_quantities.sql', -1997532057, 'root', '2026-08-06 16:16:11.0', 108, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (98, '99', 'merchant onboarding huifu kyc', 'SQL', 'V99__merchant_onboarding_huifu_kyc.sql', -2101049968, 'root', '2026-08-06 16:18:05.0', 99, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (99, '100', 'bank branch directory', 'SQL', 'V100__bank_branch_directory.sql', 1807573421, 'root', '2026-08-06 17:02:18.0', 50, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (100, '101', 'admin protocol settings', 'SQL', 'V101__admin_protocol_settings.sql', -1203779278, 'root', '2026-08-06 17:02:18.0', 20, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (101, '102', 'talent service staff assignment', 'SQL', 'V102__talent_service_staff_assignment.sql', -239485552, 'root', '2026-08-06 17:02:47.0', 58, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (102, '103', 'merchant bank card huifu business open', 'SQL', 'V103__merchant_bank_card_huifu_business_open.sql', -69951860, 'root', '2026-08-06 17:38:24.0', 77, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (103, '104', 'merchant bank card encrypted number', 'SQL', 'V104__merchant_bank_card_encrypted_number.sql', 1336670329, 'root', '2026-08-11 12:14:15.0', 139, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (104, '106', 'admin protocol four settings', 'SQL', 'V106__admin_protocol_four_settings.sql', -174261213, 'root', '2026-08-11 12:18:14.0', 31, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (105, '107', 'restore premium topic merchants', 'SQL', 'V107__restore_premium_topic_merchants.sql', 498121720, 'root', '2026-08-11 12:18:14.0', 13, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (106, '108', 'dependent card apply binding', 'SQL', 'V108__dependent_card_apply_binding.sql', 2135726729, 'root', '2026-08-11 12:18:15.0', 314, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (107, '109', 'dependent card apply schema compatibility', 'SQL', 'V109__dependent_card_apply_schema_compatibility.sql', 1039006436, 'root', '2026-08-11 12:18:15.0', 33, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (108, '110', 'sync admin protocol settings to agreements', 'SQL', 'V110__sync_admin_protocol_settings_to_agreements.sql', -718565758, 'root', '2026-08-11 12:18:15.0', 39, true); |
| | | INSERT INTO `flyway_schema_history` (`installed_rank`, `version`, `description`, `type`, `script`, `checksum`, `installed_by`, `installed_on`, `execution_time`, `success`) VALUES (109, '111', 'news article top time sorting', 'SQL', 'V111__news_article_top_time_sorting.sql', -1596820028, 'root', '2026-08-11 12:19:32.0', 112, true); |