You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SpringBoot汽车租赁系统LLD:如何实现车辆时段排他预订?

汽车租赁系统低级别设计(LLD)问题解答

背景实体类

Car 类

public class Car{
    private long id;
    private Type type;
    private String licenseNum;
    private Color color;
    private Location location;
    //other details
    //Color是枚举,值为RED、WHITE等
    //TYPE是枚举,值为SEDAN、SUV、HATCHBACK等
    //Location是包含位置相关信息的类
}

Booking 类

public class Booking{
    private long id;
    private Date bookingStartDay;//预订起始日
    private int bookingDays;//预订天数,最大值50
    private User userId;
    private Location pickUpLoc;
    private Location dropLoc;
    //User是包含用户详情(如id、姓名、地址等)的实体
}

原BookCar类(存在时段覆盖问题)

public class BookCar{
    private long carId;
    private Date bookingStartDay;
    //carId和bookingStartDay构成复合主键;
    private User user;
    private BookingStatus status;
    //BookingStatus是枚举,值为CANCELLED、RESERVED
}

原方案问题:仅记录预订起始日,导致后续日期无法被标记为已预订,其他用户可重复预订同一车辆的中间时段。


问题解答

1. 实现车辆时段排他预订的替代方案

以下是几种面试中常用的可行方案:

方案一:修改BookCar实体存储完整时间段

调整BookCar类,存储预订起始日和预订结束日,可以用单独主键ID,同时给carId、bookingStartDay、bookingEndDay添加联合唯一索引:

public class BookCar{
    private long id;
    private long carId;
    private Date bookingStartDay;
    private Date bookingEndDay; // 由bookingStartDay + bookingDays计算得出
    private User user;
    private BookingStatus status;
}

核心逻辑:当新用户发起预订时,通过SQL查询判断目标车辆是否存在时间重叠的已预订记录。重叠判断条件为:

SELECT COUNT(*) FROM book_car 
WHERE car_id = ? 
AND status = 'RESERVED'
AND booking_start_day <= ? -- 新预订的结束日
AND booking_end_day >= ?; -- 新预订的起始日

如果查询结果大于0,说明时段冲突,拒绝预订;否则允许创建预订。

方案二:使用日历表关联预订记录

提前创建一张CarCalendar表,存储每辆车每天的状态:

public class CarCalendar{
    private long carId;
    private Date date;
    private long bookingId; // 关联Booking表的ID,null表示当天可用
    private BookingStatus status;
    // carId + date 作为复合主键
}

核心逻辑:用户预订N天时,批量插入N条CarCalendar记录,标记对应日期为RESERVED并关联预订ID。查询可用性时,直接检查目标日期范围内的记录是否全部为可用状态。

方案三:基于Booking表直接做冲突校验

无需单独的BookCar类,直接扩展Booking表,添加carId字段关联Car表,然后通过时间范围冲突查询判断:

SELECT COUNT(*) FROM booking 
WHERE car_id = ? 
AND status = 'CONFIRMED'
AND booking_start_day <= ? 
AND (booking_start_day + INTERVAL booking_days DAY) >= ?;

这种方案减少了实体类数量,适合业务逻辑相对简单的场景。


2. 每日一条记录、50次写入在MySQL中是否可行?

结论:完全可行,但需注意优化细节

  • 可行性层面:MySQL单表支持高并发写入,50条批量插入操作的性能开销极低,普通配置的数据库就能轻松处理。
  • 优化建议:
    • 使用批量插入语句(如INSERT INTO book_car (car_id, booking_start_day, ...) VALUES (...), (...), ...)替代50次单条插入,减少网络IO和数据库连接开销。
    • 给carId + bookingStartDay添加联合唯一索引,避免重复插入同一车辆同一日期的记录,同时加速可用性查询。
    • 若业务量极大(如百万级车辆+每日大量预订),可考虑分表(按carId哈希分表)或分区(按日期分区)进一步提升性能。
  • 潜在缺点:该方案会导致BookCar表数据量快速增长(每辆车每年最多365条记录),但MySQL处理千万级数据的能力依然足够,只要索引设计合理,查询效率不会受太大影响。若追求更简洁的数据结构,优先选择方案一中的时间段存储方式。

内容的提问来源于stack exchange,提问作者Mayank Kumar Thakur

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 06:20:41