一. @EnableScheduling注解开启定时任务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package io.coderyeah.ymcc;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.scheduling.annotation.EnableScheduling;

@EnableScheduling//开启定时任务
@SpringBootApplication
public class KillServiceApp {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(KillServiceApp.class);
}
}

二. @Scheduled(cron = "0 0 0 * * ?")指定定时任务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import cn.hutool.core.date.DateUtil;
import io.coderyeah.ymcc.domain.KillActivity;
import io.coderyeah.ymcc.service.IKillActivityService;
import io.coderyeah.ymcc.util.AssertUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
@Slf4j
public class PublishKillCourse2Redis {
@Autowired
private IKillActivityService activityService;


// 定时发布秒杀活动到redis (0 0 1 * * ?)==>>每天凌晨一点执行一次
// 每天凌晨0点执行一次 @Scheduled(cron = "0 0 0 * * ?")
// @Scheduled(cron = "0 0/1 8-20 * * ?") // 每隔一分钟执行一次
@Scheduled(cron = "0 0 0 * * ?")// 每天凌晨0点执行一次
public void publish() {
// 查询当天的数据sql:SELECT * FROM t_kill_activity WHERE TO_DAYS(start_time) =TO_DAYS(NOW())
// 获取到当天待发布的活动
List<KillActivity> activities = activityService.getCurrentData();
AssertUtil.isNotNull(activities, "今日暂无秒杀活动发布");
// 遍历每一个活动执行发布
log.info("{}--任务准备发布到redis~~~", DateUtil.now());
activities.forEach(killActivity -> {
// 任务发布
activityService.publish(killActivity.getId());
});
log.info("{}--已发布到redis~~~", DateUtil.now());
}
}

三. 发布方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
@Autowired
private RedissonClient redissonClient;
@Autowired
private IKillCourseService courseService;
@Autowired
private RedisTemplate<Object, Object> redisTemplate;
@Autowired
private KillActivityMapper activityMapper;

@Transactional
@Override
public void publish(Long id) {
// id:发布的活动id 根据id查询当前活动
KillActivity killActivity = selectById(id);
AssertUtil.isNotNull(killActivity, "秒杀活动不存在");
// 判断活动是否开启和过期
AssertUtil.isEqualsTrim(killActivity.getPublishStatus().toString(), KillActivity.KILL_WAIT_PUBLISH.toString(), "活动已发布或已结束");
AssertUtil.isFalse(killActivity.getStartTime().after(new Date()), "活动未开启,请在规定时间发布");
AssertUtil.isFalse(killActivity.getEndTime().before(new Date()), "活动已经结束");
// 根据秒杀活动查询出所有秒杀课程
Wrapper<KillCourse> wrapper = new EntityWrapper<>();
wrapper.eq("activity_id", id);
List<KillCourse> courses = courseService.selectList(wrapper);
//更新秒杀活动状态
killActivity.setPublishTime(new Date());
killActivity.setPublishStatus(KillActivity.KILL_OK_PUBLISH);
updateById(killActivity);

courses.forEach(course -> {
// 使用hash存储秒杀课程
// 课程没有库存 使用信号量来处理超卖超买问题
// 获取信号量
RSemaphore semaphore = redissonClient.getSemaphore(course.getId().toString());
// 设置信号量 --课程秒杀的数量
boolean b = semaphore.trySetPermits(course.getKillCount());
log.info("设置信号量:{}", b);
AssertUtil.isTrue(b, "获取信号量失败");
String key = RedisConstants.KILL_ACTIVITY + id;
redisTemplate.opsForHash().put(key, course.getCourseId().toString(), course);
// 更新秒杀课程状态 秒杀中
course.setPublishStatus(KillCourse.KILLING);
course.setPublishTime(new Date());// 发布时间
courseService.updateById(course);
});
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RedissonConfig {

//创建客户端
@Bean
public RedissonClient redissonClient(){
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379").setPassword("123456");
return Redisson.create(config);
}
}
1
2
3
4
5
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.17.7</version>
</dependency>