
采用“订单状态标记无效+待撮合队列移除+对手方订单失效通知”的原子操作,通过数据库事务和乐观锁保证实时性、正确性,时间复杂度近似O(1)。
在交易撮合系统中,订单状态分为“待撮合”“已成交”“已撤”等。撤单处理的核心逻辑是:先标记订单为“已撤”,再从待撮合队列中移除,并向对手方发送订单失效通知,确保撤单后对手方不再匹配该订单。类比:订单是“待匹配的合约”,撤单相当于“合约作废”,系统不再匹配,同时通知对手方合约作废,避免后续错误匹配。
具体步骤:
| 方法 | 定义 | 特性 | 使用场景 | 注意点 |
|---|---|---|---|---|
| 立即删除 | 撤单时直接物理删除订单记录 | 逻辑简单,但可能导致数据不一致(如日志未同步) | 低并发、小流量场景 | 事务回滚复杂,恢复困难,对手方无法获知订单失效 |
| 标记无效 | 撤单时仅更新订单状态为“已撤”,不删除记录 | 逻辑健壮,支持恢复,数据一致性高 | 高并发、大流量场景(如交易所) | 需定期清理无效订单,对手方需主动查询状态 |
| 标记无效+对手方通知 | 在标记无效基础上,向对手方发送订单失效消息 | 增加对手方匹配逻辑,避免重复匹配 | 高并发、对手方系统依赖订单状态 | 需确保消息可靠传输,避免消息丢失 |
函数 handle_cancel(order_id, user_id):
1. 验证订单有效性:
SELECT * FROM orders WHERE order_id = order_id AND user_id = user_id AND status IN ('待撮合', '未成交');
若不存在或状态为“已成交”,返回错误。
2. 事务操作(乐观锁+状态更新+队列移除+日志+对手方通知):
START TRANSACTION;
-- 乐观锁:检查版本号
SELECT version FROM orders WHERE order_id = order_id FOR UPDATE;
UPDATE orders SET status = '已撤', cancel_time = now(), version = version + 1 WHERE order_id = order_id AND user_id = user_id AND version = version;
-- 从队列移除
DELETE FROM matching_queue WHERE order_id = order_id;
-- 记录日志
INSERT INTO order_log (order_id, user_id, action, time) VALUES (order_id, user_id, '撤单', now());
-- 通知对手方订单失效
SEND_MESSAGE TO opponent_system (order_id, 'order_invalid', now());
COMMIT;
3. 返回成功响应。
{
"order_id": "ORD12345",
"user_id": "U001",
"timestamp": "2024-01-15T10:30:00Z"
}
“面试官您好,处理撤单请求时,核心是采用‘状态标记+队列移除+对手方通知’的原子流程。具体来说,收到撤单请求后,先验证订单存在且状态允许撤单(如未成交),然后通过事务更新订单状态为‘已撤’,从待撮合队列删除,并记录日志。同时,向对手方订单的匹配系统发送失效通知,确保对手方不再匹配。这样既保证了撤单的实时性,又避免了对手方订单的重复匹配错误。时间复杂度上,状态更新和队列移除都是O(1)操作,整体复杂度近似O(1),适合高并发交易场景。”