添加并发布秒杀商品(1.1)

添加并发布秒杀商品(1.1),第1张

1、秒杀商品的添加:

通过后台将秒杀商品添加到秒杀表里面,设置好秒杀时间跟周期,包括状态,状态有待发布,已发布,已取消。还有秒杀商品的详情表,库存,每个人可以秒杀的数量,对应秒杀商品的id,秒杀开始,秒杀结束的时间,还包括状态待秒杀,秒杀中,秒杀结束。

2、秒杀商品的发布:

发布秒杀商品通过springBoot的定时任务每天晚上凌晨定时扫描表,查询出后两天的秒杀商品,然后存储到Redis中,存储可能存在集群多线程 *** 作来发布秒杀,做了添加到Redis中的成功还是失败判断,添加数据到Redis是有返回值Boolean,然后再通过redssion的信号量做了分布式锁来作为数量的记录。这里还要修改秒杀商品的状态为已发布,如果保存信号量失败,还要从Redis中删除商品。这里存储商品数据到Redis是通过hash结构,以一个常量作为大key,秒杀商品的id作为小key,商品的信息作为value

演示代码:

domain

/**
 * @author lyq-yyds
 */
@TableName("t_kill_course")
@Data
public class KillCourse extends Model {
	
	/**
	 * 秒杀状态 0:待发布 1:已发布 2:秒杀结束
	 */
	public static final int PUBLISH_BEFORE = 0;
	public static final int PUBLISH_ING = 1;
	public static final int PUBLISH_OVER = 2;
	
	
	private static final long serialVersionUID = 1L;
	
	@TableId(value = "id", type = IdType.AUTO)
	private Long id;
	/**
	 * 课程名字
	 */
	@TableField("course_name")
	private String courseName;
	/**
	 * 对应的课程ID
	 */
	@TableField("course_id")
	private Long courseId;
	@TableField("kill_price")
	private BigDecimal killPrice;
	/**
	 * 秒杀库存
	 */
	@TableField("kill_count")
	private Integer killCount;
	/**
	 * 每个人可以秒杀的数量,默认1
	 */
	@TableField("kill_limit")
	private Integer killLimit = 1;
	/**
	 * 秒杀课程排序
	 */
	@TableField("kill_sort")
	private Integer killSort;
	/**
	 * 秒杀状态:0待发布,1:已发布,2秒杀结束
	 */
	@TableField("publish_status")
	private Integer publishStatus;
	/**
	 * 课程图片
	 */
	@TableField("course_pic")
	private String coursePic;
	/**
	 * 秒杀开始时间
	 */
	@TableField("start_time")
	private Long startTime;
	/**
	 * 秒杀结束时间
	 */
	@TableField("end_time")
	private Long endTime;
	/**
	 * 创建时间
	 */
	@TableField("create_time")
	private Date createTime = new Date();
	/**
	 * 发布到Redis的时间
	 */
	@TableField("publish_time")
	private Date publishTime;
	/**
	 * 老师,用逗号隔开
	 */
	@TableField("teacher_names")
	private String teacherNames;
	/**
	 * 下线时间
	 */
	@TableField("offline_time")
	private Date offlineTime;
	@TableField("activity_id")
	private Long activityId;
	@TableField("time_str")
	private String timeStr;
	
	/**
	 * 秒杀码(防止脚本秒杀)
	 */
	@TableField(exist = false)
	private String killCode;
	
	
	@Override
	protected Serializable pkVal() {
		return this.id;
	}
	
	//计算秒杀时间差
	public Long getTimeDiffMill(){
		long nowTime = System.currentTimeMillis();
		//如果是秒杀中
		if(isKilling()){
			//还有多久结束
			return (getEndTime() - nowTime) / 1000;
		}else if(getKillStatusName().equals("即将秒杀!!")){
		    //未开始
			return (nowTime - getStartTime()) / 1000;
		}else {
			//秒杀结束
			return 0L;
		}
	}
	
	//秒杀状态的名字
	public String getKillStatusName() {
		//待发布
		if(this.publishStatus.equals(PUBLISH_BEFORE)){
		    return "待发布";
		}
		//已发布
		if(this.publishStatus.equals(PUBLISH_ING)){
			Long now = System.currentTimeMillis();
			if(now.longValue() < this.getStartTime().longValue()){
			    return "即将秒杀!!";
			}
			if(now.longValue() > this.getEndTime().longValue()){
				return "秒杀结束!!";
			}
			return "秒杀中";
		}
		//秒杀结束
		if(this.publishStatus.equals(PUBLISH_OVER)){
		    return "秒杀结束!!";
		}
		return null;
	}
	//颜色
	public Boolean isKilling(){
		//已发布
		if(this.publishStatus.equals(PUBLISH_ING)){
			Long now = System.currentTimeMillis();
			if(now.longValue() >= this.getStartTime().longValue() 
					&& now.longValue() <= this.getEndTime().longValue()){
				//在开始跟结束时间之间,就是秒杀中
				return true;
			}
			return false;
		}
		return false;
	}
	
}

service

/**
 * 

* 服务实现类 *

* * @author lyq-yyds */ @Service @Slf4j public class KillCourseServiceImpl extends ServiceImpl implements IKillCourseService { @Autowired private IKillActivityService iKillActivityService; @Autowired private RedisTemplate redisTemplate; @Autowired private RedissonClient redissonClient; private static final byte killConstant = 1; /** * 添加课程到秒杀 * * @param killCourse */ @Override public void addCourseToKill(KillCourse killCourse) { Long activityId = killCourse.getActivityId(); KillActivity killActivity = iKillActivityService.selectById(activityId); if (killActivity == null) { throw new MyError(ErrorCode.ILLEGAL_REQUEST.getMsg()); } Long beginTime = killActivity.getBeginTime(); Long endTime = killActivity.getEndTime(); String timeStr = killActivity.getTimeStr(); killCourse.setTimeStr(timeStr); killCourse.setStartTime(beginTime); killCourse.setEndTime(endTime); killCourse.setKillSort(0); killCourse.setPublishStatus(PUBLISH_BEFORE); insert(killCourse); } /** * 定时任务发布课程 * 1.查询秒杀课程,条件:待发布,近2天的 * 2.生成秒杀码(防止脚本秒杀) * 3.Redis防重判断,秒杀课程是否已经发布 * 4.保存秒杀课程到Redis(使用hash结构) * 5.信号量保存秒杀库存到Redis * 6.修改数据库课程状态为“已发布” */ @Override public void killCoursePublishTask() { // * 1.查询秒杀课程,条件:待发布,近2天的 Wrapper wrapper = new EntityWrapper<>(); wrapper.eq("publish_status", PUBLISH_BEFORE); Date date = new Date(); wrapper.between("start_time", date.getTime(), DateUtils.addDays(date, 2).getTime()); List killCourses = selectList(wrapper); if (killCourses.isEmpty()) { return; } /** * 存储Redis的结构 */ for (KillCourse killCourse : killCourses) { // * 2.生成秒杀码(防止脚本秒杀) String killCode = StrUtils.getRandomString(8); killCourse.setKillCode(killCode); killCourse.setPublishStatus(PUBLISH_ING); killCourse.setPublishTime(date); // * 3.Redis防重判断,秒杀课程是否已经发布* 4.保存秒杀课程到Redis(使用hash结构) //putIfAbsent这个方法能够自动不添加已添加到Redis中的数据。 Boolean putSuccess = redisTemplate.opsForHash().putIfAbsent( //大key "killCourse_KEY", //小key killCourse.getId().toString(), //value JSON.toJSONString(killCourse) ); //-判断是否添加到Redis成功 没有添加成功,就可能是已经添加到了Redis中,但是这个课程的状态没有修改 // 可能集群来 *** 作,Redis默认是单线程,但是要是部署了集群,就可能多个来 *** 作 if (!putSuccess) { log.info("课程添加到Redis失败,可能已添加到Redis中了"); //修改状态 updateById(killCourse); continue; } log.info("课程添加到Redis成功 {}", killCourse); // * 5.信号量保存秒杀库存到Redis Integer killCount = killCourse.getKillCount(); //===1.获得到一个信号量 RSemaphore semaphore = redissonClient.getSemaphore("killCounts:" + killCourse.getId().toString()); //===2.设置信号量的值 boolean semaphoreSuccess = semaphore.trySetPermits(killCount); if (!semaphoreSuccess) { //添加信号量失败,就是说秒杀的库存添加失败了,就把这一条记录删除 redisTemplate.opsForHash().delete( //大key "killCourse_KEY", //小key killCourse.getId().toString() ); //删除信号量 boolean delete = semaphore.delete(); }else { // * 6.修改数据库课程状态为“已发布” updateById(killCourse); log.info("课程成功发布秒杀到Redis!!"); } } } /** * 获取所有的秒杀课程,从缓存中 * 1.从Redis中获取得到所有的秒杀课程 */ @Override public List getKillCourse() { BoundHashOperations killCourse_key = redisTemplate.boundHashOps("killCourse_KEY"); List values = killCourse_key.values(); ArrayList killCourseList = new ArrayList<>(); values.stream().forEach(courseStr->{ killCourseList.add(JSON.parseObject(courseStr,KillCourse.class)); }); return killCourseList; } }

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/741843.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-28
下一篇 2022-04-28

发表评论

登录后才能评论

评论列表(0条)

保存