能学到什么
-
优化角度
-
redis的bitMap的使用
如何优化
这期我们主要对选课/退课业务逻辑进行优化与封装,至于其他优化请见后期。
-
优化一
在前期的话我们都是通过加锁从数据库读取用户的flag字段和读取课程的时间段,虽然这样的话不会出现什么问题,如果涉及到同一个用户并发的访问和修改flag字段时这就会涉及到锁的互斥了。其实我们只是想通过flag字段去记录某个用户某个时间段的选课记录。这么想一下创建用户的课程都能放入到redis里去操作,那修改用户的flag字段是不是也可以在redis进行操作呢?
go
复制代码
if err := database.Client.WithContext(ctx).Transaction(func(tx *gorm.DB) error { // 1. 获取课程的week和duration,这里完全可以通过map读取的。从而进一步减数少对db的访问 var course models.Course if err := tx.Model(&models.Course{}).Preload("Schedule").First(&course, req.CourseID).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return err } return err } // 2. 获取用户的flag字段 var user models.User // if err := tx.Clauses(clause.Locking{Strength: "SHARE"}).Where("id = ?", req.UserID).First(&user).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return err } return err } offset := int(course.Schedule.Week*3) + int(course.Schedule.Duration) if user.Flag.TestBit(offset) { resp.Fail(ctx, code.Fail, code.CourseSelected, code.CourseSelectedMsg) return errors.New("用户已经选过该课程") } // 4. 修改用户flag user.Flag.SetBit(offset) if err := tx.Save(&user).Error; err != nil { return err } return nil })
方案一
我们可以把每个课程的时间段分别放入到对应时间段的时间里,如果选的课程对应的集合和用户已选的课程存在交集的话,那么就存在时间冲突了,这样的话我们无需通过修改user表的flag字段也能进行操作,避免了直接对数据库层操作,而是内存层面上的计算。
暂时无法在飞书文档外展示此内容
虽