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 的意思是:查询期间锁住这些行,其他事务想操作同一个技师的时间段必须等我提交完才能继续。这样两个并发请求一定是一个成功一个失败,不会双重预约。

posted @ 2026-03-14 12:08  yongliu  阅读(6)  评论(0)    收藏  举报