台账做到三期,账号那块早不用我们操心了,学校 LDAP 直接管。这回加的是设备预约:谁、哪台仪器、哪段时间,别撞车。
冲突比想象中绕
一开始想简单了:同一台设备、同一个起始时间,不能重复。建个唯一索引 (device_id, slot_start) 就完事。
真用起来发现不对。有人约 9 点到 11 点,另一个人约 10 点到 12 点,起始时间不同,但中间那一个小时重叠了,一台设备没法同时干两件事。
改成区间判断。写入前先跑一条:
SELECT 1 FROM bookings WHERE device_id = 某个 AND status = 有效 AND slot_start < 新结束时间 AND slot_end > 新开始时间 LIMIT 1
查到就回「这段时间已经有约」。这条套在事务里,配合 device_id 加 slot_start 的唯一索引一起用:唯一索引挡完全相同的重复提交,区间查询挡重叠。两道都在,光靠应用层判断拦不住并发。
时段怎么切
不让人随便填分钟。设备按 30 分钟一格,界面上是点选格子,一天 48 格。这样 slot_start 和 slot_end 都是整齐的值,判断简单,导出也好看。有几台仪器一次最少要 2 小时,单独加了个 min_slots 配置。
LDAP 那头
预约人身份直接取 LDAP 里的学工号,本地只存 uid、姓名、角色。本科生只能约工作日白天,研究生和教师不限,这个映射写在角色表里,没写死在代码里。有人毕业,学校那边一停用,这边自然就约不了了。
提醒
预约成功往企业微信推一条,带设备名、时段、地点。开始前 30 分钟再推一条。推送失败不影响预约写库,只记日志,这个规矩从 2020 年活动站点那次就定下了。
12 月 5 号
上线头一周,冲突提示弹了 20 多次,多数是同一间屋子的两台设备被当成一台约了,其实不冲突。后来在列表里加了房间号一列,一眼能分清。
有老师反馈说周末想约,但本科生角色被挡了。没改代码,在角色表里给他单独加了个例外,留了备注。

