You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

列车预订系统运作机制及并发订票场景的数据处理问询

列车座位预订系统的运作逻辑与并发冲突处理

一、常规预订流程

正常的高并发预订系统都会有一套防冲突机制,核心流程是:

  • 数据库里的train_seats表会记录每个座位的状态:available(可用)、locked(临时锁定)、booked(已售出)
  • 用户选座后,系统会把选中的座位标记为locked,并设置10-15分钟的锁定超时时间——这一步是为了防止其他人同时抢同一个座位
  • 用户在锁定时间内完成支付,系统就把座位状态改成booked,绑定用户ID,生成正式订单
  • 如果用户超时没付钱,系统自动把座位改回available,释放给其他用户

二、你描述的极端场景(无预锁定,两人同时支付)

如果系统没做预锁定,允许两个用户同时选中这2个座位并完成支付,最终结果和数据库更新取决于系统用的并发控制策略:

谁能拿到座位?

只会有一个用户拿到这2个座位,另一个用户的钱会被退回。具体谁能抢到,看数据库的冲突处理逻辑:

  • 乐观锁方案:座位表有个version字段,每次更新都会让版本号+1。第一个完成支付并成功更新数据库的用户(比如用户1)会把座位状态改成booked,版本号也更新了;用户2再更新时,会发现版本号不对,座位也不是可用状态,更新直接失败。
  • 悲观锁方案:系统在更新座位时会先给对应的数据库记录加锁。用户1先发起请求,系统锁住这2个座位的记录,完成更新后才释放锁;用户2的请求会等锁释放,等拿到锁时发现座位已经被订了,更新失败。

数据库具体怎么更新?

乐观锁场景

  1. 用户1的支付请求先落地,执行更新语句:
    UPDATE train_seats 
    SET status = 'booked', user_id = 1, version = version + 1 
    WHERE train_id = 'G123' AND seat_id IN ('A1', 'A2') AND status = 'available' AND version = 0;
    
  2. 数据库返回“受影响2行”,更新成功,事务提交,同时生成订单表记录(关联用户1和这两个座位)。
  3. 用户2的更新语句执行时,version已经变成1,且座位状态是booked,数据库返回“受影响0行”,更新失败。
  4. 系统触发退款流程,把用户2的钱原路退回,同时在订单表把用户2的订单标记为失败,新增退款记录。

悲观锁场景

  1. 用户1的请求先到,系统先执行带锁的查询:
    SELECT * FROM train_seats 
    WHERE train_id = 'G123' AND seat_id IN ('A1', 'A2') AND status = 'available' FOR UPDATE;
    
  2. 数据库锁住这两条座位记录,用户1的事务继续把座位状态改成booked,绑定用户ID,提交事务后释放锁。
  3. 用户2的请求执行同样的查询时,会被卡住等待锁释放;锁释放后查询发现座位已经是booked,更新操作直接失败。
  4. 同样触发退款,更新用户2的订单状态为失败,新增退款记录。

三、额外提醒

实际生产环境里不会出现这种情况,因为预锁定是标配——让用户先锁座再付钱,避免付了钱却拿不到座的糟心体验,也能减少退款的运维成本。

内容的提问来源于stack exchange,提问作者Jigar

火山引擎 最新活动