From 621b51974f9baae62f81f523fa2ac8741dd304a5 Mon Sep 17 00:00:00 2001
From: yeg <1347747024@qq.com>
Date: 星期二, 15 九月 2026 22:37:38 +0800
Subject: [PATCH] fix(merchant): 开发库补齐进件进度表,初始化器增加建表路径

---
 talent-card-server/src/main/java/com/talentcard/server/business/merchant/MerchantOnboardingSchemaInitializer.java |   69 ++++++++++++++++++++++++++++++++++
 1 files changed, 68 insertions(+), 1 deletions(-)

diff --git a/talent-card-server/src/main/java/com/talentcard/server/business/merchant/MerchantOnboardingSchemaInitializer.java b/talent-card-server/src/main/java/com/talentcard/server/business/merchant/MerchantOnboardingSchemaInitializer.java
index ebd21fd..dc366f1 100644
--- a/talent-card-server/src/main/java/com/talentcard/server/business/merchant/MerchantOnboardingSchemaInitializer.java
+++ b/talent-card-server/src/main/java/com/talentcard/server/business/merchant/MerchantOnboardingSchemaInitializer.java
@@ -10,19 +10,63 @@
 import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.stereotype.Component;
 
-/** Keeps merchant onboarding additive columns available when Flyway is disabled in the deployment. */
+/** Keeps merchant onboarding additive tables and columns available when Flyway is disabled in the deployment. */
 @Slf4j
 @Component
 public class MerchantOnboardingSchemaInitializer implements ApplicationRunner {
     /** DDL 等锁上限:拿不到就放弃这一列,绝不把整个服务拖住。 */
     private static final int DDL_LOCK_WAIT_TIMEOUT_SECONDS = 5;
+
+    /**
+     * 进件新增的表,与迁移里的建表语句逐字对齐(V144)。
+     *
+     * <p>开发库(和任何 `spring.flyway.enabled=false` 的部署)不会自动补表:Flyway 不跑,而这个
+     * 初始化器原来只会加列。结果是 V144 建的两张表在开发库永远不存在,`GET
+     * /api/merchant/onboarding/status` 的第一个请求就以
+     * `Table 'talent_card.merchant_onboarding_progress' doesn't exist` 500——测试库有 Flyway,
+     * 看不出来。
+     */
+    private static final Map<String, String> TABLES = new LinkedHashMap<>();
+    static {
+        TABLES.put("merchant_onboarding_progress", """
+                create table if not exists merchant_onboarding_progress (
+                    application_id bigint not null primary key,
+                    stages_json text not null,
+                    last_synced_at datetime null,
+                    sync_error varchar(512) not null default '',
+                    sync_owner varchar(36) null,
+                    sync_until datetime null,
+                    updated_at datetime not null default current_timestamp on update current_timestamp
+                )""");
+        TABLES.put("merchant_onboarding_attempt", """
+                create table if not exists merchant_onboarding_attempt (
+                    id bigint not null auto_increment primary key,
+                    application_id bigint not null,
+                    step varchar(24) not null,
+                    request_no varchar(32) not null,
+                    request_date char(8) not null,
+                    apply_no varchar(32) null,
+                    status varchar(24) not null,
+                    response_code varchar(32) null,
+                    response_message varchar(512) null,
+                    created_at datetime not null default current_timestamp,
+                    unique key uk_onboarding_attempt_request (request_no),
+                    key idx_onboarding_attempt_step (application_id, step, id)
+                )""");
+    }
+
     private final JdbcTemplate jdbc;
 
     public MerchantOnboardingSchemaInitializer(JdbcTemplate jdbc) { this.jdbc = jdbc; }
 
+    static Map<String, String> tableDdl() { return Map.copyOf(TABLES); }
+
     @Override
     public void run(ApplicationArguments args) {
         try {
+            for (Map.Entry<String, String> table : TABLES.entrySet()) {
+                if (!hasTable(table.getKey())) createTable(table.getKey(), table.getValue());
+            }
             Map<String, String> columns = new LinkedHashMap<>();
             columns.put("merchant_name", "varchar(128) default null");
             columns.put("merchant_short_name", "varchar(128) default null");
@@ -118,6 +162,29 @@
         }
     }
 
+    /** 与 {@link #addColumn} 同样地失败即放弃:缺表只影响进件进度,不能让整个服务起不来。 */
+    private void createTable(String tableName, String ddl) {
+        try {
+            jdbc.execute("set session lock_wait_timeout = " + DDL_LOCK_WAIT_TIMEOUT_SECONDS);
+            jdbc.execute(ddl);
+            log.info("Merchant onboarding schema: created table {}", tableName);
+        } catch (Exception exception) {
+            log.warn("Merchant onboarding schema: could not create {} within {}s (table busy); it will be retried on the next restart. cause={}",
+                    tableName, DDL_LOCK_WAIT_TIMEOUT_SECONDS, exception.getClass().getSimpleName());
+        }
+    }
+
+    private boolean hasTable(String tableName) throws Exception {
+        try (Connection connection = jdbc.getDataSource().getConnection();
+             ResultSet result = connection.getMetaData().getTables(connection.getCatalog(), null, tableName, new String[] { "TABLE" })) {
+            if (result.next()) return true;
+        }
+        try (Connection connection = jdbc.getDataSource().getConnection();
+             ResultSet result = connection.getMetaData().getTables(connection.getCatalog(), null, tableName.toUpperCase(), new String[] { "TABLE" })) {
+            return result.next();
+        }
+    }
+
     private boolean hasColumn(String tableName, String columnName) throws Exception {
         try (Connection connection = jdbc.getDataSource().getConnection(); ResultSet result = connection.getMetaData().getColumns(connection.getCatalog(), null, tableName, columnName)) {
             if (result.next()) return true;

--
Gitblit v1.7.1