golang新建预约冲突检测
写 SQL 查一下没有冲突,然后再插入,在并发下会出问题——两个请求同时查,都发现"没冲突",然后都插入成功,结果同一个技师同一个时间段有两个预约。
解法是用 MySQL 的排他锁,查和插放在同一个事务里:
gofunc (r *BookingRepo) Create(ctx context.Context, b *Booking) error {
return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
// FOR UPDATE 加锁,同一技师同时段的其他请求会等待
var count int64
tx.Raw(`
SELECT COUNT(*) FROM bookings
WHERE tenant_id = ?
AND staff_id = ?
AND status NOT IN ('已取消','爽约')
AND start_time < ?
AND end_time > ?
FOR UPDATE
`, b.TenantID, b.StaffID, b.EndTime, b.StartTime).Scan(&count)
if count > 0 {
return errors.New("该时段已被占用")
}
// 锁住了,安全插入
return tx.Create(b).Error
})
}
FOR UPDATE 的意思是:查询期间锁住这些行,其他事务想操作同一个技师的时间段必须等我提交完才能继续。这样两个并发请求一定是一个成功一个失败,不会双重预约。
浙公网安备 33010602011771号