年会抽奖实现
最近接手的项目中要新增一个抽奖功能,场景类似年会上的抽奖,触发抽奖的只有一个动作,不存在多线程操作导致所抽奖品已经被抽完的情况。简单来说,就是不存在需要锁的场景,也不存在数据同步的情况。
这种场景的抽奖是最容易实现的,我这里的实现思路就是首先获取参与抽奖的总数,然后根据奖品数量生成几个随机数来确定中奖者。
我这里的实现首先需要上传奖品,然后上传抽奖名单,最后再根据奖品类别和数据库中未中奖用户的数量来生成随机数:
// 奖品 type Gift struct { gorm.Model Name string `json:"name" gorm:"type:varchar(32)"` // 奖品名称 GiftType int `json:"giftType"` // 奖品类别 Number int `json:"number"` // 奖品数据 } type Gifts struct { Gifts []*Gift `json:"gifts"` } func (p *Gift) TableName() string { return "gifts" } func (p *Gift) Create(ctx context.Context, db *gorm.DB) error { tx := db.Begin() if err := tx.Save(p).Error; err != nil { tx.Rollback() return err } tx.Commit() return nil } // 抽奖人员 type Awarder struct { Name string `json:"name" gorm:"type:varchar(32)"` // 抽奖人员名称 ID string `json:"id" gorm:"primarykey;type:varchar(32)"` // 抽奖人员id Prize string `json:"prize" gorm:"type:varchar(32);default:prize"` // 奖品 } func (a Awarder) Equal(o Awarder) bool { if a.Name != o.Name { return false } if a.ID != o.ID { return false } return true } type Awarders struct { Awarders []*Awarder `json:"awarders"` } func (p *Awarder) TableName() string { return "awarders" } func (p *Awarder) Create(ctx context.Context, db *gorm.DB) error { tx := db.Begin() if err := tx.Save(p).Error; err != nil { tx.Rollback() return err } tx.Commit() return nil } type Draw struct { GiftType int `json:"giftType" form:"giftType"` } func award(ctx *gin.Context) { draw := &Draw{} if err := ctx.Bind(draw); err != nil { log.Errorf("Call award function error: %s", err.Error()) ctx.JSON(http.StatusBadRequest, gin.H{"code": http.StatusBadRequest, "msg": err.Error()}) return } gift := &Gift{} if err := dbHandler.Model(&Gift{}).Where(&Gift{GiftType: draw.GiftType}).First(gift).Error; err != nil { log.Errorf("Get gifts from db error: %s", err.Error()) ctx.JSON(http.StatusOK, gin.H{"code": http.StatusInternalServerError, "msg": err.Error()}) return } if gift.Number == 0 { log.Infof("there is no gift with name: %s", gift.Name) ctx.JSON(http.StatusBadRequest, gin.H{"code": http.StatusBadRequest, "msg": fmt.Sprintf("there is no gift with name: %s", gift.Name)}) return } var awarders []Awarder if err := dbHandler.Model(&Awarder{}).Where("prize = ?", "prize").Find(&awarders).Error; err != nil { log.Errorf("Get awarders from db error: %s", err.Error()) ctx.JSON(http.StatusOK, gin.H{"code": http.StatusInternalServerError, "msg": err.Error()}) return } if len(awarders) == 0 { log.Info("there is no body without prize") ctx.JSON(http.StatusBadRequest, gin.H{"code": http.StatusBadRequest, "msg": "there is no body without prize"}) return } var winner []Awarder if gift.Number > len(awarders) { winner = make([]Awarder, len(awarders)) } else { winner = make([]Awarder, gift.Number) } for i := 0; i < len(winner); i++ { if gift.Number == 0 { log.Info("no gift with name: %s", gift.Name) break } gift.Number -= 1 index, err := rand.Int(rand.Reader, big.NewInt(int64(len(winner)))) if err != nil { log.Errorf("Gen random number error: %s", err.Error()) ctx.JSON(http.StatusOK, gin.H{"code": http.StatusInternalServerError, "msg": err.Error()}) return } awarder := awarders[index.Int64()] awarder.Prize = gift.Name awarder.Create(context.TODO(), dbHandler) awarders = delAwarder(awarders, awarder) winner[i] = awarder } gift.Create(context.TODO(), dbHandler) ctx.JSON(http.StatusOK, gin.H{"code": http.StatusOK, "msg": "success", "data": winner}) } func delAwarder(awarders []Awarder, awarder Awarder) []Awarder { i := 0 for _, v := range awarders { if !v.Equal(awarder) { awarders[i] = v i++ } } return awarders[:i] }
声明:本作品采用署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)进行许可,使用时请注明出处。
Author: mengbin92
Github: mengbin92
cnblogs: 恋水无意
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
2017-11-26 添砖加瓦:snappy无损压缩算法