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
相关产品推荐
相关产品推荐

