会议室预约如何判断冲突:从时间区间到并发控制
会议室预约看起来只是填写房间和起止时间,却有几个容易忽略的问题:上一场十点结束,下一场能否十点开始?取消的预约是否继续占用房间?两个人同时提交怎么办?
下面用一个小型物业应用场景说明设计思路。代码是说明性示例,尚未运行验证,不代表已部署项目的实测结果。
一、明确时间边界
将预约表示为半开区间 [开始时间, 结束时间),包含开始时刻,不包含结束时刻。因此,09:00—10:00 与 10:00—11:00 可以相邻安排。
已有预约为 [a, b),新预约为 [c, d),重叠条件是:
a < d and c < b
只比较同一会议室、仍占用资源的预约。取消记录可以保留用于追溯,但不再占用时段。如果需要清洁缓冲时间,应明确扩展占用区间。
二、最小判断示例
以下示例约定 confirmed 状态占用资源,时间参数必须是带时区的 Python datetime。
def overlaps(existing, proposed):
for item in (existing, proposed):
start, end = item['start'], item['end']
if start.utcoffset() is None or end.utcoffset() is None:
raise ValueError('时间必须携带时区')
if end <= start:
raise ValueError('结束时间必须晚于开始时间')
return (
existing['room_id'] == proposed['room_id']
and existing['status'] == 'confirmed'
and proposed['status'] == 'confirmed'
and existing['start'] < proposed['end']
and proposed['start'] < existing['end']
)
接口接收输入时,还需校验字段类型、房间是否存在、状态值是否合法,以及开放时段和预约时长。时间可统一存储为 UTC,展示时转换为楼宇所在地时区。
三、前端提示不能替代后端校验
前端可以提示冲突、展示空闲时段,但客户端参数可以被修改。服务端必须重新校验用户身份、房间使用权限、预约时间和状态。
冲突提示也不应泄露其他预约人的姓名或会议内容,返回“该时段不可用”通常就够了。
四、并发请求需要数据库保护
重叠函数无法防止两个请求同时查到空闲,再分别写入。
应将冲突复查与写入放入同一事务,并采用适合数据库的并发控制。例如在支持行锁的数据库中,先锁定对应房间记录,再查询冲突并写入;所有预约入口都必须遵守相同协议。只锁已有预约行并不充分,因为空时段可能没有记录可锁。
数据库支持时,可以使用房间与有效时间区间的排斥约束作为最后防线。普通唯一约束不能识别任意区间重叠;采用可串行化隔离时,也要处理事务失败与重试。
可靠的预约功能,需要时间规则、服务端校验和数据库并发控制共同配合,而不只是一个重叠公式。
- 点赞
- 收藏
- 关注作者
评论(0)