添加注解 调用定时器:
@EnableScheduling
@Component
@Slf4j
@RequiredArgsConstructor
public class LikedTimesCheckTask {
/* 定时任务扫描 redis 点赞总数zset 集合 ,获取点赞数 发送MQ 消息*/
/*业务类型的集合:QA(问答) "NoTe 笔记"*/
private final myTimecountsconfig myTimecountsconfig;
// 两个类型 定义两个常量:::::
private static final int MAX_BIZ_SIZE = 30; // 每次去取多少:::
private final ILikedRecordService recordService; // 注入业务层
@Scheduled(fixedDelay = 20000) // 20000 毫秒co fix 20000 固定时间 时间
public void checkLikedTimes(){
for (String bizType : myTimecountsconfig.getBIZ_TYPES()) {
recordService.readLikedTimesAndSendMessage(bizType, MAX_BIZ_SIZE); // 根据业务类型 然后去取多少数据:
}
}
}
业务层注入 创建业务
@XxlJob("issueCoupon") / @XxlJob 注解可以直接把优惠卷发放
@XxlJob("issueCoupon") /
public void PromotionTask(){
//1、查询需要发放的优惠券数据:
// select * from 优惠券表 where status = 未开始 and 发放开始时间[issueBeginTime] <= 当前时间
// 如果没有查询出数据,则直接返回
List<Coupon> list = couponService.lambdaQuery()
.eq(Coupon::getStatus, CouponStatus.UN_ISSUE)
.lt(Coupon::getIssueBeginTime, LocalDateTime.now()).list();
if (CollUtils.isEmpty(list)){
return;
}
//TODO 优惠券
//2、循环遍历优惠券,更新优惠券的状态为发放中 CouponStatus.ISSUING 把2变3
for (Coupon coupon : list) {
couponService.lambdaUpdate()
.set(Coupon::getStatus,CouponStatus.ISSUING.getValue())
.eq(Coupon::getId,coupon.getId())
.update();
// 还要判断是否需要生成兑换码,如果需要则使用SpringAsync异步操作生成验证码
// 判断条件: 优惠券类型必须是兑换码,且优惠券状态必须是待发放
if(coupon.getObtainWay()== ObtainType.ISSUE && coupon.getStatus()==CouponStatus.DRAFT){
coupon.setIssueEndTime(coupon.getTermEndTime());
exchangeCodeService.generateExchangeCode(coupon);
}
业务代码编写 好 mq 打包发送
使用mq需要1. 导入依赖 2. 配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
/*根据业务类型批量从redis 的 zset 集合中读取不同业务的点赞数量 发送mq 消息 并且持久化到数据库 查询的时候再继续加载*/
@Override
public void readLikedTimesAndSendMessage(String bizType, int maxBizSize) {
// 先移除点赞总数 数据转换 发送消息:
// 1.读取并移除Redis中缓存的点赞总数 String LIKE_BIZ_KEY_PREFIX = "likes:set:biz:{}"
// popMin 取出zset 集合中分数最少的前30个 点赞数最少的前多少个 ::: 这个命令
String zsetkey = StringUtils.format(RedisConstants.LIKE_BIZ_KEY_PREFIX,bizType);
// ps 如果是空的直接返回: 从zset集合中去取出分数最少的:
Set<ZSetOperations.TypedTuple<String>> set = redisTemplate.opsForZSet().popMin(zsetkey,maxBizSize); // key 去取的数量 30 个 从定时任务器中已经弄出来了
if (CollUtils.isEmpty(set)) {
return;
}
// 2.数据转换 读取是上面的set Set<ZSetOperations.TypedTuple<String>> set 里面的数据包含两个: 业务 Id score分数 点赞数
ArrayList<LikedTimesDTO> dtoList = new ArrayList<>();
for (ZSetOperations.TypedTuple<String> tuple : set) {
Double score = tuple.getScore(); //点赞次数
Long bizId = Long.valueOf(tuple.getValue()); // 业务
if (ObjectUtils.isEmpty(bizId) || ObjectUtils.isNull(score)) {
continue;
}
LikedTimesDTO dto = new LikedTimesDTO(Long.valueOf(bizId), score.intValue());
dtoList.add(dto);
}
// 3.批量修改点赞数量 发送mq 一个一个发比较好: 这边打包发送:
if (CollUtils.isNotEmpty(dtoList)){ // 如果不为空
log.info("需要更新点赞数的业务有" ,dtoList);
mqHelper.send(MqConstants.Exchange.LEARNING_EXCHANGE, // 交换机
StringUtils.format(MqConstants.Key.LIKED_TIMES_KEY_TEMPLATE,bizType), // 路由key
dtoList // 内容
);
}
编写一个监听器 监听到打包发来的dtolist数据然后更改数据库
@Component
@RequiredArgsConstructor
@Slf4j
public class LikeTImesChangeListener {
private final IInteractionReplyService replyService;
@RabbitListener(
bindings = {
@QueueBinding(
value = @Queue(MqConstants.Queue.QA_LIKED_TIMES_QUERE),
exchange = @Exchange(name = MqConstants.Exchange.LEARNING_EXCHANGE),
key = {MqConstants.Key.QA_LIKED_TIMES_KEY}
)
}
)
public void likedTimesChange(List<LikedTimesDTO> dtoList){
log.info("监听到消息并且点赞数变更");
for (LikedTimesDTO dto : dtoList) {
replyService.lambdaUpdate()
.set(InteractionReply::getLikedTimes,dto.getLikedTimes())
.eq(InteractionReply::getId,dto.getBizId())
.update();
}
}
}