需求 redis中数据同步到mysql中数据,如果在更新途中redis又更新了,按照Redis中最新的数据进行更新。
实现思路:存储redis数据用RedisTemplate.opsForValue进行数据存储,在数据发生改变的时候,优先向redis中更新数据,然后先一个set集合中add新的数据的key值。业务端的操作就结束了,接下来通过一个专门的定时任务服务,通过设置@Scheduled(fixedDelay = 500)设置一个任务专门从上面的存放key值的set中pop出key值,然后从redis中查询出来,再通过这个key值更新到对应的mysql数据库中,这个任务从启动就开始执行,执行结束后等待fixedDelay后设置的毫秒时间,又接着执行下一次该任务。以此往复,就会将前台发送至set中的key对应的redis数据更新至mysql中,以实现数据同步。
/**
* 更新Redis中User信息
* @param userUid 用户uid
* @param user User对象
*/
public void saveUser(int userUid,User user){
try {
redisLockUtil.lock("userLock-uid:" + userUid);
log.info("userLock-uid: " + userUid + "上锁");
String userData = JSONObject.toJSONString(user);
redisTemplate.opsForValue().set("user-uid:" + userUid, userData, 7, TimeUnit.DAYS);
redisTemplate.opsForSet().add("redis-update-queue", "user-uid:"+userUid);
//向更新列表set中发送需要更新的数据的key
} catch (Exception e) {
log.error(e.getMessage(), e);
} finally {
redisLockUtil.unlock("userLock-uid:" + userUid);
log.info("userLock-uid: " + 10135 + "解锁");
}
}
在定时任务中还可以采用自定义线程池的方式手动设置线程数量等参数,以达到最优的更新mysql的效率。
@EnableAsync
@Configuration
@Slf4j
public class UserDataUpdateQueue {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private UserDao userDao;
@Async("taskExecutor")
@Scheduled(fixedDelay = 500)
public void getUserUpdateQueue() {
log.info("------getUserUpdateQueue------");
while (redisTemplate.opsForSet().size("xyddz-redis-update-queue") > 0) {
List<Object> pop = redisTemplate.opsForSet().pop("xyddz-redis-update-queue", 10);
for (Object userData : pop) {
String userStr = (String) redisTemplate.opsForValue().get(userData.toString());
if (!StringUtils.isEmpty(userStr)) {
User user = JSONObject.parseObject(userStr, User.class);
userDao.save(user);
log.info("更新User-Uid:" + user.getUid());
}
}
}
}
}
Post Views: 122