Redis和MySQL的双写一致性指的是在同时使用缓存和数据库存储数据的时候,保证Redis和MySQL中数据的一致性。用户发起请求,先从Redis中查取数据,有数据就直接返回,没有数据就从MySQL中查询数据,并且存储到Redis中,然后返回。从MySQL中查询到数据再存入Redis中这个步骤称为回写。
func(dao * UserDAO) FindByID(c context.Context, userID int64)(u domain.User, err error) { db: =dao.db rdb: =dao.rdb key: =fmt.Sprintf("user:%v", userID) // 堆代码 duidaima.com // 1. 从缓存中查询数据,如果有数据就返回 var user domain.User val, err: =rdb.Get(c, key).Result() if val != "" && err == nil { err: =json.Unmarshal([] byte(val), &user) if err == nil { return user, nil } } // 2. 没有查到数据就加锁再查一次 mu.Lock() defer mu.Unlock() val, err = rdb.Get(c, key).Result() // 2.1 从缓存中查到数据就直接返回 if val != "" && err == nil { err: =json.Unmarshal([] byte(val), &user) if err == nil { return user, nil } } // 2.2 没有从缓存中查到数据就从数据库中查询 err = db.Where("id=?", userID).First( & user).Error if err != nil { return user, err } // 3. 将从数据库中拿到的数据写到缓存中 userStr, err: =json.Marshal(user) if err == nil { rdb.Set(c, key, userStr, 1000 * time.Second) } return user, nil }
数据库和缓存一致性的几种更新策略
上面说的是查询策略,接下来说一下数据库和缓存一致性的更新策略。比如先往MySQL中灌入1万条数据,再同步到Redis中,可以在凌晨升级,给出升级提示。
func (dao *UserDAO) UpdateUserData(c context.Context, userID int64, name string) (user User, err error) { db := dao.db rdb := dao.rdb key := fmt.Sprintf("user:%v", userID) user.ID = userID // 先更新数据库中的数据 u := User{ Name: name, } err = db.Model(&user). Select("Name"). Where("id=?", userID).Updates(u).Error if err != nil { return user, err } // 再删除缓存中的数据 err = rdb.Del(c, key).Err() if err != nil { return user, err } return user, nil }5.比较稳妥的方式