Files
baiyue-firstleg/order/src/main/resources/db/order.sql
T

352 lines
22 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
SET NAMES utf8mb4;
-- 订单服务独占数据库。其他服务只能通过 OpenAPI 或领域事件获取订单数据。
CREATE DATABASE IF NOT EXISTS baiyue_order
DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
USE baiyue_order;
CREATE TABLE IF NOT EXISTS ord_order (
id BIGINT UNSIGNED NOT NULL COMMENT '订单ID(雪花ID)',
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '客户ID和数据隔离键',
order_no VARCHAR(32) NOT NULL COMMENT '客户范围内唯一订单号',
inbound_code VARCHAR(40) NULL COMMENT '全平台唯一入仓码;来源由全局模式决定,提交后固定',
customer_id BIGINT UNSIGNED NULL COMMENT '客户逻辑ID',
customer_name VARCHAR(128) NOT NULL COMMENT '下单时客户名称快照',
status VARCHAR(24) NOT NULL DEFAULT 'DRAFT' COMMENT '订单业务状态:DRAFT草稿、SUBMITTED已提交、APPROVED审核通过、ACCEPTED已接单、REJECTED审核驳回、PROCESSING履约中、COMPLETED已完成、CANCELLED已取消',
transport_mode VARCHAR(16) NOT NULL COMMENT '运输方式',
trade_term VARCHAR(16) NULL COMMENT '贸易条款',
destination_country_code CHAR(2) NOT NULL COMMENT '目的国家二字码',
destination_warehouse_id BIGINT UNSIGNED NULL COMMENT '目的仓逻辑ID',
destination_warehouse_name VARCHAR(128) NOT NULL COMMENT '目的仓名称快照',
expected_ship_date DATE NULL COMMENT '预计发运日期',
customer_remark VARCHAR(1000) NULL COMMENT '客户可见备注',
pickup_method VARCHAR(24) NULL COMMENT '取货方式',
requested_pickup_at DATETIME(3) NULL COMMENT '客户要求平台上门提货的预约时间',
receiving_warehouse_id BIGINT UNSIGNED NULL COMMENT '国内收货仓ID',
receiving_warehouse_name VARCHAR(128) NULL COMMENT '国内收货仓快照',
receiving_warehouse_address VARCHAR(512) NULL COMMENT '国内收货仓完整地址快照',
receiving_time VARCHAR(128) NULL COMMENT '国内收货仓收货时间快照',
channel_code VARCHAR(64) NULL COMMENT '渠道编码',
channel_name VARCHAR(128) NULL COMMENT '渠道名称快照',
carrier_id BIGINT UNSIGNED NULL COMMENT '船司逻辑ID快照',
carrier_name VARCHAR(128) NULL COMMENT '船司名称快照',
tax_mode VARCHAR(24) NULL COMMENT '买单或退税',
pricing_tax_mode VARCHAR(16) NULL COMMENT '报价包税维度:TAX_INCLUDED或TAX_EXCLUDED;独立于tax_mode',
container_mode VARCHAR(24) NULL COMMENT '整柜或散货',
customs_inspection TINYINT(1) NULL COMMENT '是否商检',
destination_type VARCHAR(24) NULL COMMENT '目的仓类型:FBA亚马逊仓、OVERSEAS海外仓、PRIVATE私人地址',
fulfillment_type VARCHAR(32) NOT NULL DEFAULT 'STANDARD' COMMENT '履约类型:STANDARD普通头程、ONE_CLICK_DROPSHIP一键代发',
amazon_warehouse_code VARCHAR(32) NULL COMMENT '亚马逊仓库编码',
shipment_id VARCHAR(64) NULL COMMENT '订单级Amazon Shipment ID',
reference_id VARCHAR(64) NULL COMMENT '订单级Amazon Reference ID',
order_role VARCHAR(12) NOT NULL DEFAULT 'MASTER' COMMENT '订单层级:MASTER主订单、CHILD子订单',
parent_order_id BIGINT UNSIGNED NULL COMMENT '直属父订单ID;主订单为空;禁止子订单嵌套',
root_order_id BIGINT UNSIGNED NULL COMMENT '根主订单ID',
split_sequence INT UNSIGNED NULL COMMENT '同一父订单下的同级子订单顺序',
express_company VARCHAR(64) NULL COMMENT '履约快递公司名称快照',
express_tracking_no VARCHAR(128) NULL COMMENT '履约快递单号',
submitted_at DATETIME(3) NULL COMMENT '提交时间',
completed_at DATETIME(3) NULL COMMENT '完成时间',
created_by BIGINT UNSIGNED NOT NULL COMMENT '创建人ID',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
updated_by BIGINT UNSIGNED NOT NULL COMMENT '最后修改人ID',
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
PRIMARY KEY (id),
UNIQUE KEY uk_order_tenant_no (tenant_id, order_no),
UNIQUE KEY uk_order_inbound_code (inbound_code),
KEY idx_order_tenant_status_time (tenant_id, status, created_at),
KEY idx_order_tenant_role_submitted (tenant_id, order_role, submitted_at),
KEY idx_order_tenant_customer (tenant_id, customer_id),
KEY idx_order_tenant_warehouse (tenant_id, destination_warehouse_id)
) ENGINE=InnoDB COMMENT='头程订单主表:保存商户委托、目的仓、运输方式和订单当前状态';
SET @order_fulfillment_type_sql = IF(
EXISTS(
SELECT 1 FROM information_schema.columns
WHERE table_schema = 'baiyue_order' AND table_name = 'ord_order'
AND column_name = 'fulfillment_type'
),
'SELECT 1',
'ALTER TABLE baiyue_order.ord_order ADD COLUMN fulfillment_type VARCHAR(32) NULL COMMENT ''履约类型:STANDARD普通头程、ONE_CLICK_DROPSHIP一键代发'' AFTER destination_type'
);
PREPARE order_fulfillment_type_stmt FROM @order_fulfillment_type_sql;
EXECUTE order_fulfillment_type_stmt;
DEALLOCATE PREPARE order_fulfillment_type_stmt;
UPDATE baiyue_order.ord_order
SET fulfillment_type = 'STANDARD'
WHERE fulfillment_type IS NULL OR fulfillment_type = '';
ALTER TABLE baiyue_order.ord_order
MODIFY COLUMN fulfillment_type VARCHAR(32) NOT NULL DEFAULT 'STANDARD'
COMMENT '履约类型:STANDARD普通头程、ONE_CLICK_DROPSHIP一键代发';
-- 既有开发库必须先确认不存在跨客户重复码;若存在则在此处失败,不自动改写业务数据。
SET @order_global_inbound_index_sql = IF(
NOT EXISTS(
SELECT 1 FROM information_schema.statistics
WHERE table_schema = 'baiyue_order' AND table_name = 'ord_order'
AND index_name = 'uk_order_inbound_code'
),
'ALTER TABLE baiyue_order.ord_order ADD UNIQUE KEY uk_order_inbound_code (inbound_code)',
'SELECT 1'
);
PREPARE order_global_inbound_index_stmt FROM @order_global_inbound_index_sql;
EXECUTE order_global_inbound_index_stmt;
DEALLOCATE PREPARE order_global_inbound_index_stmt;
SET @order_tenant_inbound_index_drop_sql = IF(
EXISTS(
SELECT 1 FROM information_schema.statistics
WHERE table_schema = 'baiyue_order' AND table_name = 'ord_order'
AND index_name = 'uk_order_tenant_inbound_code'
),
'ALTER TABLE baiyue_order.ord_order DROP INDEX uk_order_tenant_inbound_code',
'SELECT 1'
);
PREPARE order_tenant_inbound_index_drop_stmt FROM @order_tenant_inbound_index_drop_sql;
EXECUTE order_tenant_inbound_index_drop_stmt;
DEALLOCATE PREPARE order_tenant_inbound_index_drop_stmt;
-- Existing development databases may still have the former NOT NULL contract.
SET @order_inbound_code_nullable_sql = IF(
EXISTS(
SELECT 1 FROM information_schema.columns
WHERE table_schema = 'baiyue_order' AND table_name = 'ord_order'
AND column_name = 'inbound_code' AND is_nullable = 'NO'
),
'ALTER TABLE baiyue_order.ord_order MODIFY COLUMN inbound_code VARCHAR(40) NULL COMMENT ''全平台唯一入仓码;来源由全局模式决定,提交后固定''',
'SELECT 1'
);
PREPARE order_inbound_code_nullable_stmt FROM @order_inbound_code_nullable_sql;
EXECUTE order_inbound_code_nullable_stmt;
DEALLOCATE PREPARE order_inbound_code_nullable_stmt;
SET @order_requested_pickup_at_sql = IF(
EXISTS(
SELECT 1 FROM information_schema.columns
WHERE table_schema = 'baiyue_order' AND table_name = 'ord_order'
AND column_name = 'requested_pickup_at'
),
'SELECT 1',
'ALTER TABLE baiyue_order.ord_order ADD COLUMN requested_pickup_at DATETIME(3) NULL COMMENT ''客户要求平台上门提货的预约时间'' AFTER pickup_method'
);
PREPARE order_requested_pickup_at_stmt FROM @order_requested_pickup_at_sql;
EXECUTE order_requested_pickup_at_stmt;
DEALLOCATE PREPARE order_requested_pickup_at_stmt;
CREATE TABLE IF NOT EXISTS ord_inbound_code_daily_sequence (
business_date DATE NOT NULL COMMENT '上海时区业务日期',
current_value BIGINT UNSIGNED NOT NULL COMMENT '当天全平台已分配票数',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '当天首次分配时间',
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '最近分配时间',
PRIMARY KEY (business_date)
) ENGINE=InnoDB COMMENT='入仓码每日票序;不同客户和物流渠道共用,按上海日期重新从1开始';
CREATE TABLE IF NOT EXISTS ord_order_fulfillment_split (
id BIGINT UNSIGNED NOT NULL COMMENT '拆分台账ID',
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '客户ID和数据隔离键',
parent_order_id BIGINT UNSIGNED NOT NULL COMMENT '直属父订单ID;主订单作为拆分根',
source_order_id BIGINT UNSIGNED NOT NULL COMMENT '本次实际消费的主订单或余量子订单ID',
child_order_id BIGINT UNSIGNED NOT NULL COMMENT '本次分片承接的子订单ID',
split_role VARCHAR(12) NOT NULL COMMENT '本台账分片角色:LOADED已装柜部分、REMAINDER剩余部分',
loading_plan_id BIGINT UNSIGNED NULL COMMENT 'Firstleg装柜计划逻辑ID',
container_booking_id BIGINT UNSIGNED NULL COMMENT 'Firstleg柜次逻辑ID',
source_package_count INT UNSIGNED NOT NULL COMMENT '来源订单本次分片前的总包装件数',
loaded_package_count INT UNSIGNED NOT NULL COMMENT '本次已装柜分片包装件数',
remaining_package_count INT UNSIGNED NOT NULL COMMENT '本次分片后剩余包装件数',
source_detail_json JSON NULL COMMENT '来源货物明细及箱数快照',
operation_id VARCHAR(64) NOT NULL COMMENT '履约分片业务操作ID',
idempotency_key VARCHAR(128) NOT NULL COMMENT '客户端幂等键',
request_hash CHAR(64) NOT NULL COMMENT '规范化请求内容SHA-256摘要',
expected_parent_version INT NOT NULL COMMENT '执行前预期父订单乐观锁版本号',
created_by BIGINT UNSIGNED NOT NULL COMMENT '创建该分片台账的用户ID',
created_by_name VARCHAR(64) NULL COMMENT '创建人名称快照',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '台账创建时间',
version INT NOT NULL DEFAULT 0 COMMENT '台账乐观锁版本号',
PRIMARY KEY (id),
UNIQUE KEY uk_order_split_operation (tenant_id, operation_id, split_role),
UNIQUE KEY uk_order_split_idempotency (tenant_id, parent_order_id, idempotency_key, split_role),
UNIQUE KEY uk_order_split_child_role (tenant_id, child_order_id, split_role),
KEY idx_order_split_parent (tenant_id, parent_order_id, created_at, id),
KEY idx_order_split_source (tenant_id, source_order_id, split_role),
KEY idx_order_split_container (tenant_id, container_booking_id, created_at, id),
CONSTRAINT fk_order_split_parent FOREIGN KEY (parent_order_id) REFERENCES ord_order(id),
CONSTRAINT fk_order_split_child FOREIGN KEY (child_order_id) REFERENCES ord_order(id),
CONSTRAINT chk_order_split_quantity CHECK (
source_package_count > 0 AND loaded_package_count > 0
AND loaded_package_count + remaining_package_count = source_package_count
)
) ENGINE=InnoDB COMMENT='父订单到子订单的装柜数量及柜次关联台账';
DROP TRIGGER IF EXISTS trg_order_fulfillment_split_insert;
DROP TRIGGER IF EXISTS trg_order_fulfillment_split_update;
DELIMITER $$
CREATE TRIGGER trg_order_fulfillment_split_insert
BEFORE INSERT ON ord_order_fulfillment_split FOR EACH ROW
BEGIN
IF NEW.split_role NOT IN ('LOADED','REMAINDER') THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='订单履约分片角色非法';
END IF;
IF NEW.split_role='LOADED' AND NEW.child_order_id<>NEW.source_order_id THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='实装台账必须由来源订单自身承接';
END IF;
IF NEW.split_role='REMAINDER'
AND (NEW.child_order_id=NEW.source_order_id OR NEW.remaining_package_count=0) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='余量台账必须指向有剩余数量的新子订单';
END IF;
END$$
CREATE TRIGGER trg_order_fulfillment_split_update
BEFORE UPDATE ON ord_order_fulfillment_split FOR EACH ROW
BEGIN
IF NOT (NEW.tenant_id<=>OLD.tenant_id)
OR NOT (NEW.parent_order_id<=>OLD.parent_order_id)
OR NOT (NEW.source_order_id<=>OLD.source_order_id)
OR NOT (NEW.child_order_id<=>OLD.child_order_id)
OR NOT (NEW.split_role<=>OLD.split_role) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='订单履约分片来源、子片与角色不可修改';
END IF;
END$$
DELIMITER ;
CREATE TABLE IF NOT EXISTS ord_order_party (
id BIGINT UNSIGNED NOT NULL COMMENT '参与方快照ID',
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '客户ID和数据隔离键',
order_id BIGINT UNSIGNED NOT NULL COMMENT '所属订单ID',
party_type VARCHAR(16) NOT NULL COMMENT '参与方类型:SHIPPER或CONSIGNEE',
company_name VARCHAR(128) NOT NULL COMMENT '公司名称快照',
contact_name VARCHAR(64) NOT NULL COMMENT '联系人快照',
phone VARCHAR(32) NOT NULL COMMENT '联系电话快照',
email VARCHAR(128) NULL COMMENT '联系邮箱快照',
country_code CHAR(2) NOT NULL COMMENT '国家二字码',
province VARCHAR(64) NULL COMMENT '省/州',
city VARCHAR(64) NOT NULL COMMENT '城市',
district VARCHAR(64) NULL COMMENT '区县',
address_line VARCHAR(255) NOT NULL COMMENT '详细地址',
postal_code VARCHAR(20) NULL COMMENT '邮政编码',
created_by BIGINT UNSIGNED NOT NULL COMMENT '创建人ID',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
updated_by BIGINT UNSIGNED NOT NULL COMMENT '最后修改人ID',
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
PRIMARY KEY (id),
UNIQUE KEY uk_party_order_type (tenant_id, order_id, party_type),
CONSTRAINT fk_party_order FOREIGN KEY (order_id) REFERENCES ord_order (id)
) ENGINE=InnoDB COMMENT='订单收发货方快照表:固化下单时发货人和收货人信息,避免主数据变化影响历史订单';
CREATE TABLE IF NOT EXISTS ord_order_cargo (
id BIGINT UNSIGNED NOT NULL COMMENT '货物明细ID',
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '客户ID和数据隔离键',
order_id BIGINT UNSIGNED NOT NULL COMMENT '所属订单ID',
item_no INT NOT NULL COMMENT '订单内明细序号',
cargo_name VARCHAR(128) NULL COMMENT '货物名称;草稿可空,提交前必填',
hs_code VARCHAR(20) NULL COMMENT '海关商品编码',
package_type VARCHAR(32) NULL COMMENT '包装类型;草稿可空,提交前必填',
package_count INT UNSIGNED NOT NULL COMMENT '包装件数',
gross_weight_kg DECIMAL(18,3) NULL COMMENT '毛重(千克);草稿可空,提交前必须大于0',
volume_cbm DECIMAL(18,4) NULL COMMENT '体积(立方米);草稿可空,提交前必须大于0',
length_cm DECIMAL(12,2) NULL COMMENT '单件长度(厘米)',
width_cm DECIMAL(12,2) NULL COMMENT '单件宽度(厘米)',
height_cm DECIMAL(12,2) NULL COMMENT '单件高度(厘米)',
declared_value DECIMAL(18,2) NULL COMMENT '申报价值',
currency CHAR(3) NULL COMMENT '币种三字码',
dangerous_goods TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否危险品',
cargo_remark VARCHAR(500) NULL COMMENT '货物备注',
sku_no VARCHAR(64) NULL COMMENT '货物SKU编码',
upc_no VARCHAR(64) NULL COMMENT '货物UPC条码',
cargo_name_en VARCHAR(128) NULL COMMENT '英文品名',
customs_hs_code VARCHAR(20) NULL COMMENT '目的国清关HS CODE',
units_per_package INT UNSIGNED NULL COMMENT '每箱件数',
total_quantity INT UNSIGNED NULL COMMENT '总件数',
net_weight_kg DECIMAL(18,3) NULL COMMENT '净重kg',
unit_declared_value DECIMAL(18,2) NULL COMMENT '单件申报价值',
material VARCHAR(128) NULL COMMENT '材质',
product_usage VARCHAR(128) NULL COMMENT '用途',
model VARCHAR(64) NULL COMMENT '型号',
brand VARCHAR(64) NULL COMMENT '品牌',
product_length_cm DECIMAL(12,2) NULL COMMENT '产品长度(厘米)',
product_width_cm DECIMAL(12,2) NULL COMMENT '产品宽度(厘米)',
product_height_cm DECIMAL(12,2) NULL COMMENT '产品高度(厘米)',
shipment_id VARCHAR(64) NULL COMMENT '货物级 Amazon Shipment ID',
reference_id VARCHAR(64) NULL COMMENT '货物级 Amazon Reference ID',
product_image_file_id BIGINT UNSIGNED NULL COMMENT '文件中心产品图片逻辑ID',
created_by BIGINT UNSIGNED NOT NULL COMMENT '创建人ID',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
updated_by BIGINT UNSIGNED NOT NULL COMMENT '最后修改人ID',
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
PRIMARY KEY (id),
UNIQUE KEY uk_cargo_item (tenant_id, order_id, item_no),
KEY idx_cargo_order (tenant_id, order_id),
CONSTRAINT fk_cargo_order FOREIGN KEY (order_id) REFERENCES ord_order (id)
) ENGINE=InnoDB COMMENT='订单货物明细表:记录件数、重量、体积、申报价值和危险品属性';
CREATE TABLE IF NOT EXISTS ord_order_internal_note (
id BIGINT UNSIGNED NOT NULL COMMENT '内部备注ID',
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '客户ID和数据隔离键',
order_id BIGINT UNSIGNED NOT NULL COMMENT '所属订单ID',
content VARCHAR(2000) NOT NULL COMMENT '仅内部人员可见的备注内容',
created_by BIGINT UNSIGNED NOT NULL COMMENT '创建人ID',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
updated_by BIGINT UNSIGNED NOT NULL COMMENT '最后修改人ID',
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
PRIMARY KEY (id),
KEY idx_note_order_time (tenant_id, order_id, created_at),
CONSTRAINT fk_note_order FOREIGN KEY (order_id) REFERENCES ord_order (id)
) ENGINE=InnoDB COMMENT='订单内部备注表:保存平台运营或履约人员的内部协作记录,不向商户客户展示';
CREATE TABLE IF NOT EXISTS ord_order_status_history (
id BIGINT UNSIGNED NOT NULL COMMENT '状态历史ID',
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '客户ID和数据隔离键',
order_id BIGINT UNSIGNED NOT NULL COMMENT '所属订单ID',
from_status VARCHAR(24) NULL COMMENT '变更前状态,首次创建可为空',
to_status VARCHAR(24) NOT NULL COMMENT '变更后状态',
action VARCHAR(24) NOT NULL COMMENT '触发状态变化的业务动作',
reason VARCHAR(500) NULL COMMENT '变更原因',
operator_id BIGINT UNSIGNED NOT NULL COMMENT '操作人ID',
operator_name VARCHAR(64) NULL COMMENT '操作人名称快照',
occurred_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '状态变化时间',
PRIMARY KEY (id),
KEY idx_history_order_time (tenant_id, order_id, occurred_at),
CONSTRAINT fk_history_order FOREIGN KEY (order_id) REFERENCES ord_order (id)
) ENGINE=InnoDB COMMENT='订单状态不可变历史表:按时间记录每次状态迁移、动作、原因和操作人';
CREATE TABLE IF NOT EXISTS ord_outbox_event (
id BIGINT UNSIGNED NOT NULL COMMENT '领域事件全局ID,同时作为消费幂等键',
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '事件所属客户ID和数据隔离键',
aggregate_type VARCHAR(32) NOT NULL COMMENT '聚合类型,例如 ORDER',
aggregate_id BIGINT UNSIGNED NOT NULL COMMENT '发生变更的聚合根ID,例如订单ID',
event_type VARCHAR(64) NOT NULL COMMENT '领域事件类型,例如 ORDER_SUBMITTED',
payload_json JSON NOT NULL COMMENT '供下游消费的事件负载快照',
publish_status VARCHAR(16) NOT NULL DEFAULT 'PENDING' COMMENT '发布状态:PENDING待发布、PUBLISHED已发布、FAILED发布失败',
retry_count INT NOT NULL DEFAULT 0 COMMENT '投递失败后的累计重试次数',
next_retry_at DATETIME(3) NULL COMMENT '允许再次投递的最早时间',
published_at DATETIME(3) NULL COMMENT '成功发布到消息中间件的时间',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '事件在本地事务中的创建时间',
PRIMARY KEY (id),
KEY idx_outbox_publish (publish_status, next_retry_at, created_at)
) ENGINE=InnoDB COMMENT='订单事务Outbox表:与订单业务变更在同一本地事务写入,供后台发布器可靠投递RocketMQ,保证数据库状态与领域事件最终一致;不是普通操作日志';
CREATE TABLE IF NOT EXISTS ord_idempotency_record (
id BIGINT UNSIGNED NOT NULL COMMENT '幂等记录ID',
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '客户ID和数据隔离键',
operator_id BIGINT UNSIGNED NOT NULL COMMENT '操作者ID',
operation VARCHAR(32) NOT NULL COMMENT '幂等操作类型',
resource_id BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '资源ID,创建草稿时为0',
idempotency_key VARCHAR(128) NOT NULL COMMENT '客户端幂等键',
request_hash CHAR(64) NOT NULL COMMENT '请求内容SHA-256摘要',
status VARCHAR(16) NOT NULL COMMENT '处理状态:PROCESSING处理中、COMPLETED已完成',
result_order_id BIGINT UNSIGNED NULL COMMENT '成功结果订单ID',
completed_at DATETIME(3) NULL COMMENT '处理完成时间',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
PRIMARY KEY (id),
UNIQUE KEY uk_order_idempotency_scope (tenant_id, operator_id, operation, idempotency_key),
KEY idx_order_idempotency_created (created_at)
) ENGINE=InnoDB COMMENT='订单写接口持久化幂等记录:唯一键保证同租户同操作者并发请求只执行一次';