本地消息表是用于解决业务操作与消息发送的原子性问题,本文主要针对 RocketMQ 来说。

1、 首先一个表肯定要有主键 ID。

2、因为本地消息表是为消息服务的,所以要有一个字段存储消息内容

3、还要有一个字段存储具体的 Topic

4、为了幂等性,需要标识消息的状态,已经发送了还是待发送

5、为了防止消息一直重试,增加重试次数

6、模拟延时队列,增加下一次重试时间

7、还有上一次执行时间

8、如果多业务共用一张表,还需要增加业务字段,用来区分业务

9、增加业务幂等键

10、创建时间与修改时间

11、创建代码类(系统)和修改代码类(系统)

整理成表格的话:

字段名 类型 允许为空 默认值 说明
id BIGINT(20) NOT NULL AUTO_INCREMENT 主键 ID
biz_key VARCHAR(64) NOT NULL 业务幂等键,用于防止重复处理同一业务消息
biz_type VARCHAR(32) NOT NULL 业务类型(如 order_createstock_update
topic VARCHAR(64) NOT NULL 消息所属 RocketMQ Topic
message_body TEXT NOT NULL 消息内容(建议存储 JSON 序列化后的数据)
status TINYINT(3) NOT NULL 0 消息状态:0-待发送,1-发送中,2-已发送,3-发送失败
retry_count INT(11) NOT NULL 0 重试次数
next_retry_time DATETIME YES NULL 下次重试时间(用于模拟延时队列)
last_execute_time DATETIME YES NULL 上一次执行(发送)时间
fail_reason VARCHAR(255) YES NULL 发送失败原因(错误码、异常信息摘要)
create_by VARCHAR(64) YES NULL 创建人(代码类名/系统名)
update_by VARCHAR(64) YES NULL 最后更新人(代码类名/系统名)
gmt_create DATETIME NOT NULL CURRENT_TIMESTAMP 创建时间
gmt_modified DATETIME NOT NULL CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP 修改时间

索引上,根据查询条件设置:


-- 扫描待发送的消息
CREATE INDEX idx_state_nextretry ON local_message (state, next_retry_time);

-- 按业务幂等键查找
CREATE UNIQUE INDEX uk_biz_type_key ON local_message (biz_type, biz_key);

-- 按 topic 查找
CREATE INDEX idx_topic ON local_message (topic);

CREATE TABLE `t_local_message` (
    `id`                bigint          NOT NULL AUTO_INCREMENT COMMENT '主键ID',
    `biz_type`          varchar(64)     NOT NULL COMMENT '业务类型(区分不同业务,例如order_create、stock_lock等)',
    `biz_key`           varchar(128)    NOT NULL COMMENT '业务幂等键(关联具体业务记录,例如订单号)',
    `topic`             varchar(255)    NOT NULL COMMENT 'RocketMQ Topic',
    `message_body`      text            NOT NULL COMMENT '消息内容(JSON格式)',
    `status`            tinyint         NOT NULL COMMENT '消息状态:0-待发送,1-发送中,2-已发送,3-发送失败',
    `retry_count`       int             NOT NULL DEFAULT 0 COMMENT '消息已重试次数',
    `next_retry_time`   datetime        DEFAULT NULL COMMENT '下一次重试时间(可实现延时发送)',
    `last_exec_time`    datetime        DEFAULT NULL COMMENT '最后一次发送时间',
    `fail_reason`       varchar(512)    DEFAULT NULL COMMENT '最后一次失败原因',
    `created_by`        varchar(64)     NOT NULL COMMENT '创建人或系统代码标识',
    `updated_by`        varchar(64)     NOT NULL COMMENT '修改人或系统代码标识',
    `gmt_create`        datetime        NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    `gmt_modified`      datetime        NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
    PRIMARY KEY (`id`),
    UNIQUE KEY `uk_biz_type_key` (`biz_type`, `biz_key`) COMMENT '业务幂等约束',
    KEY `idx_status_next_retry` (`status`, `next_retry_time`) COMMENT '扫描待重试的消息',
    KEY `idx_topic` (`topic`) COMMENT '按 topic 查找'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='本地消息表(生产者侧)';

                ┌───────────────────────┐
                │ 0 待发送               │
                │(事务提交后写入表)      │
                └──────────┬────────────┘
                           │ 定时任务扫描(status=0)
                           ▼
                ┌───────────────────────┐
                │ 1 发送中               │
                │(调用 MQ 发送接口)      │
                └───────┬───────┬───────┘
                        │       │
          MQ 发送成功   │       │ MQ 发送失败
                        │       ▼
                        │   ┌────────────────────────────┐
                        │   │ 记录 fail_reason            │
                        │   │ retry_count += 1           │
                        │   │ 设置 next_retry_time        │
                        │   └───────────┬────────────────┘
                        │               │
                        │               ▼
                        │   达到最大重试次数?
                        │          │
                        │          │ 否
                        │          ▼
                        │     回到 1 发送中(下次扫描)
                        │
                        ▼
          ┌────────────────────────────┐
          │ 2 已发送                    │
          │(成功投递至 Broker,归档或删) │
          └────────────────────────────┘

                                 │
                                 │ 是
                                 ▼
                        ┌───────────────────────┐
                        │ 3 发送失败             │
                        │(人工处理或补偿机制)     │
                        └───────────────────────┘