chore(deploy): synchronize phase3 unified database migration
This commit is contained in:
@@ -16,7 +16,6 @@ CALL phase3_order_add_column('ord_order','order_role',"VARCHAR(12) NOT NULL DEFA
|
||||
CALL phase3_order_add_column('ord_order','parent_order_id','BIGINT UNSIGNED NULL COMMENT ''直属父订单ID;禁止子订单嵌套''');
|
||||
CALL phase3_order_add_column('ord_order','root_order_id','BIGINT UNSIGNED NULL COMMENT ''根主订单ID''');
|
||||
CALL phase3_order_add_column('ord_order','split_sequence','INT UNSIGNED NULL COMMENT ''同一父订单下的同级顺序''');
|
||||
DROP PROCEDURE IF EXISTS phase3_order_add_column;
|
||||
|
||||
DROP PROCEDURE IF EXISTS phase3_order_add_index;
|
||||
DELIMITER $$
|
||||
@@ -33,7 +32,6 @@ CALL phase3_order_add_index('ord_order','uk_order_parent_sequence',
|
||||
'UNIQUE KEY `uk_order_parent_sequence` (`tenant_id`,`parent_order_id`,`split_sequence`)');
|
||||
CALL phase3_order_add_index('ord_order','idx_order_root_role',
|
||||
'KEY `idx_order_root_role` (`tenant_id`,`root_order_id`,`order_role`,`created_at`,`id`)');
|
||||
DROP PROCEDURE IF EXISTS phase3_order_add_index;
|
||||
|
||||
DROP PROCEDURE IF EXISTS phase3_order_parent_fk;
|
||||
DELIMITER $$
|
||||
@@ -118,7 +116,14 @@ DELIMITER ;
|
||||
CALL phase3_order_add_column('ord_order_fulfillment_split','split_role',"VARCHAR(12) NOT NULL DEFAULT 'LOADED' COMMENT 'LOADED或REMAINDER'");
|
||||
CALL phase3_order_add_column('ord_order_fulfillment_split','source_order_id','BIGINT UNSIGNED NULL COMMENT ''实际被消费的来源订单ID''');
|
||||
CALL phase3_order_add_column('ord_order_fulfillment_split','request_hash',"CHAR(64) NULL COMMENT '请求内容SHA-256;存量记录允许为空'");
|
||||
-- 存量空来源必须先由发布前数据核对补齐;P0 契约不允许继续写无来源台账。
|
||||
-- 旧版台账没有来源字段;当时只允许从根主订单拆分,因此可无歧义回填为父订单。
|
||||
UPDATE ord_order_fulfillment_split
|
||||
SET source_order_id = parent_order_id
|
||||
WHERE source_order_id IS NULL;
|
||||
-- 旧记录没有请求哈希。生成稳定哨兵哈希可保持非空约束,并让旧幂等键重放明确冲突。
|
||||
UPDATE ord_order_fulfillment_split
|
||||
SET request_hash = SHA2(CONCAT('LEGACY:', tenant_id, ':', id), 256)
|
||||
WHERE request_hash IS NULL OR request_hash = '';
|
||||
ALTER TABLE ord_order_fulfillment_split
|
||||
MODIFY source_order_id BIGINT UNSIGNED NOT NULL COMMENT '实际被消费的来源订单ID',
|
||||
MODIFY request_hash CHAR(64) NOT NULL COMMENT '请求内容SHA-256';
|
||||
@@ -145,6 +150,8 @@ CALL phase3_order_add_index('ord_order_fulfillment_split','uk_order_split_operat
|
||||
'UNIQUE KEY `uk_order_split_operation` (`tenant_id`,`operation_id`,`split_role`)');
|
||||
CALL phase3_order_add_index('ord_order_fulfillment_split','uk_order_split_idempotency',
|
||||
'UNIQUE KEY `uk_order_split_idempotency` (`tenant_id`,`parent_order_id`,`idempotency_key`,`split_role`)');
|
||||
DROP PROCEDURE IF EXISTS phase3_order_add_column;
|
||||
DROP PROCEDURE IF EXISTS phase3_order_add_index;
|
||||
|
||||
DROP PROCEDURE IF EXISTS phase3_order_assert;
|
||||
DELIMITER $$
|
||||
@@ -158,6 +165,17 @@ BEGIN
|
||||
AND table_name='ord_order_fulfillment_split')<>1 THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='订单拆分台账未创建';
|
||||
END IF;
|
||||
IF (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema=DATABASE()
|
||||
AND table_name='ord_order_fulfillment_split'
|
||||
AND column_name IN ('source_order_id','request_hash') AND is_nullable='NO')<>2 THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='订单拆分来源和请求哈希必须为非空';
|
||||
END IF;
|
||||
IF (SELECT COUNT(DISTINCT index_name) FROM information_schema.statistics
|
||||
WHERE table_schema=DATABASE() AND table_name='ord_order_fulfillment_split'
|
||||
AND index_name IN ('idx_order_split_source','uk_order_split_operation',
|
||||
'uk_order_split_idempotency'))<>3 THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='订单拆分来源或幂等索引未完整创建';
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
CALL phase3_order_assert();
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.baiyue.order.repository;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class OrderParentChildSqlContractTest {
|
||||
|
||||
@Test
|
||||
void sourceAndRequestHashAreRequiredAndHelpersLiveUntilFinalCall() throws Exception {
|
||||
String sql = read(resolveModule());
|
||||
|
||||
assertThat(sql)
|
||||
.contains("source_order_id BIGINT UNSIGNED NOT NULL")
|
||||
.contains("KEY idx_order_split_source (tenant_id,source_order_id,split_role)")
|
||||
.contains("MODIFY source_order_id BIGINT UNSIGNED NOT NULL")
|
||||
.contains("MODIFY request_hash CHAR(64) NOT NULL")
|
||||
.contains("UPDATE ord_order_fulfillment_split")
|
||||
.contains("SHA2(CONCAT('LEGACY:', tenant_id, ':', id), 256)");
|
||||
assertThat(sql.lastIndexOf("DROP PROCEDURE IF EXISTS phase3_order_add_column"))
|
||||
.isGreaterThan(sql.lastIndexOf("CALL phase3_order_add_column"));
|
||||
assertThat(sql.lastIndexOf("DROP PROCEDURE IF EXISTS phase3_order_add_index"))
|
||||
.isGreaterThan(sql.lastIndexOf("CALL phase3_order_add_index"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void unifiedEntryContainsTheExactOrderBlockBeforeFirstleg() throws Exception {
|
||||
String unified = read(resolve("deploy/sql/头程数据库统一增量-MySQL8.sql"));
|
||||
String module = read(resolveModule()).trim();
|
||||
String marker = "-- 来源:order/src/main/resources/db/phase3-order-parent-child-schema.sql";
|
||||
String next = "-- 来源:firstleg/src/main/resources/db/phase3-inbound-parent-child-schema.sql";
|
||||
int start = unified.indexOf(marker);
|
||||
int end = unified.indexOf(next, start + marker.length());
|
||||
|
||||
assertThat(start).isGreaterThanOrEqualTo(0);
|
||||
assertThat(end).isGreaterThan(start);
|
||||
assertThat(unified.substring(start + marker.length(), end).trim()).startsWith(module);
|
||||
assertThat(unified.lastIndexOf("SELECT 'PASS' AS migration_status"))
|
||||
.isGreaterThan(end);
|
||||
}
|
||||
|
||||
private static Path resolve(String path) {
|
||||
Path direct = Path.of(path);
|
||||
return Files.exists(direct) ? direct : Path.of("..", path).normalize();
|
||||
}
|
||||
|
||||
private static Path resolveModule() {
|
||||
Path direct = Path.of("src/main/resources/db/phase3-order-parent-child-schema.sql");
|
||||
return Files.exists(direct)
|
||||
? direct
|
||||
: Path.of("order/src/main/resources/db/phase3-order-parent-child-schema.sql");
|
||||
}
|
||||
|
||||
private static String read(Path path) throws Exception {
|
||||
return Files.readString(path, StandardCharsets.UTF_8)
|
||||
.replace("\r\n", "\n")
|
||||
.replace("\uFEFF", "");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user