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  阅读(1)  评论(0)    收藏  举报