在现代预约系统中,时间管理是至关重要的环节。尤其在像 在线辅导平台 这样的场景中,教师可能会因临时事务、休假或其他原因,将原定的可预约时间替换为备用时间(alternative time)。如何在 API 中设计替代规则,既保证数据一致性,又简化客户端处理逻辑,同时保持扩展性,是我们要探讨的核心问题。
在 预约系统中,我们需要处理以下场景:
- 教师预设了固定的可预约时间段
- 教师临时调整,指定某个时间段不可用,但提供了替代时间
- 学生在客户端查询可用时间时,不应看到无效时间
- 需保证客户端缓存不会导致显示过期或无效的时间段
✅ 设计目标
- 确保学生无法预约已被替代的时间段
- 保持数据一致性,防止客户端缓存过期显示无效时间
- 提供清晰、可扩展的 API,便于未来维护
在涉及替代时间的场景中,数据一致性优先,因此服务端应负责处理替代逻辑。
原因:
- 服务端具备全局视角,能够准确判断哪些时间段无效
- 客户端缓存数据可能会滞后,导致显示过期时间
- 简化客户端逻辑,减少客户端处理复杂性
✅ 结论:
- 替代时间段应在服务端直接替换掉原时间段
- 客户端只需展示有效时间段,无需关心替代逻辑
做法:
- 服务端返回常规时间 + 替代时间段
- 客户端根据
is_replaced
标志位过滤无效时间
问题:
- 增加客户端复杂性
- 客户端缓存时间过长,可能导致显示已被替代的时间
- 多端一致性难以保证
✅ 结论:
- 将复杂的替代规则交给服务端处理,有助于保持数据一致性
- 客户端只展示有效时间段,减少出错几率
首先,我们设计数据表结构,记录常规时间和替代时间。
CREATE TABLE tutor_availability (
id SERIAL PRIMARY KEY,
tutor_id INT NOT NULL,
date DATE NOT NULL,
start_time TIME NOT NULL,
end_time TIME NOT NULL,
is_replaced BOOLEAN DEFAULT false, -- 是否被替代
alternative_start TIME, -- 替代时间段
alternative_end TIME
);
is_replaced
: 标记该时间段是否被替代alternative_start
和alternative_end
: 替代时间段
查询有效时间段
- 服务端在查询时合并替代时间段
- 返回的时间段只包含有效时间
📌 SQL查询示例
-- 查询有效时间段(替代时间优先)
SELECT
tutor_id,
date,
COALESCE(alternative_start, start_time) AS start_time,
COALESCE(alternative_end, end_time) AS end_time
FROM tutor_availability
WHERE date = '2025-04-01'
AND (is_replaced = false OR (alternative_start IS NOT NULL AND alternative_end IS NOT NULL));
✅ 返回结果
{
"tutor_id": "67890",
"date": "2025-04-01",
"available_slots": [
{
"start_time": "2025-04-01T10:30:00Z",
"end_time": "2025-04-01T11:30:00Z"
}
]
}
def get_available_slots(tutor_id, date):
slots = query_database(tutor_id, date)
# 合并替代时间段
available_slots = []
for slot in slots:
if slot['is_replaced'] and slot['alternative_start'] and slot['alternative_end']:
# 替代时间段
available_slots.append({
"start_time": slot['alternative_start'],
"end_time": slot['alternative_end']
})
elif not slot['is_replaced']:
# 常规时间段
available_slots.append({
"start_time": slot['start_time'],
"end_time": slot['end_time']
})
return available_slots
✅ 解释
- 查询数据库时,将替代时间与常规时间合并
- 服务端仅返回有效时间段
问题:客户端缓存可能导致数据不一致
- 如果客户端缓存数据过久,可能导致显示过期时间段
解决方案
- 服务端返回当前数据版本号
- 客户端缓存数据时附带版本号
- 每次查询时比较版本号,不一致时刷新数据
✅ API 响应示例
{
"version": "2025-04-01T10:00:00Z", // 服务端数据版本
"available_slots": [
{
"start_time": "2025-04-01T10:30:00Z",
"end_time": "2025-04-01T11:30:00Z"
}
]
}
✅ 客户端逻辑
- 若客户端缓存版本号与服务端版本号一致,使用缓存数据
- 若版本号不同,清理缓存,重新加载数据
✅ ① Redis缓存
- 将教师可预约时间缓存至 Redis
- 变更替代时间时,自动清理缓存
- 减少数据库查询压力
✅ ② WebSocket实时通知
- 教师修改时间后,实时通知客户端刷新数据
- 减少客户端数据过期问题
✅ ③ 并发处理
- 幂等性:使用
Idempotency-Key
防止重复预订 - 乐观锁或事务,防止时间段被重复预订
✅ 选择服务端处理替代时间
- 数据一致性更强,客户端只展示有效时间
- 减少客户端逻辑复杂度
✅ 缓存版本号机制
- 返回时间数据版本号,防止客户端缓存失效问题
- 客户端判断版本号,保持数据同步
✅ 优化方向
- Redis缓存时间段
- WebSocket实时通知
- 并发与幂等性处理
💡 通过服务端处理替代时间,我们不仅能保证数据一致性,还能简化客户端逻辑,减少缓存问题。同时,配合缓存优化和版本号校验,能确保学生在客户端看到的永远是有效时间段。 😎