SeckillStatus:
package com.kejin.seckill.bean;
import lombok.Data;
import java.io.Serializable;
@Data
public class SeckillStatus implements Serializable {
//秒杀状态 1排队中 2秒杀等待支付 3支付超时 4支付失败 5支付完成
private Integer status;
//商品id
private Long goodsId;
//用户id
private Long userId;
//订单号
private Long orderId;
}
User:
package com.kejin.seckill.bean;
import lombok.Data;
import java.io.Serializable;
@Data
public class User implements Serializable {
private Long id;
private String userName;
}
RedisCacheConfig:
package com.kejin.seckill.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;
@Component
public class RedisCacheConfig {
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate redisTemplate = new RedisTemplate();
redisTemplate.setConnectionFactory(redisConnectionFactory);
// 使用Jackson2JsonRedisSerialize 替换默认序列化
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
// 设置value的序列化规则和 key的序列化规则
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(redisTemplate.getKeySerializer());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
SeckillConstant:
package com.kejin.seckill.constant;
public class SeckillConstant {
//商品库存信息
public static String seckillStock ="goods:seckill:stock:";
//保存秒杀队列记录,避免重复下单
public static String seckillOrderCount ="goods:seckill:order:count:";
//查看下单状态
public static String seckillOrderStatus ="goods:seckill:order:status:";
//查看秒杀订单信息
public static String seckillOrderInfo ="goods:seckill:order:info:";
//秒杀成功的订单
public static String seckillOrderSuccess ="goods:seckill:order:success:";
}
SeckillController:
package com.kejin.seckill.controller;
import com.kejin.seckill.service.SeckillService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@ResponseBody
public class SeckillController {
@Autowired
private SeckillService seckillService;
@GetMapping("/testSeckill")
public Boolean findById(){
return seckillService.placeOrder();
}
}
RedisPreHeat:
package com.kejin.seckill.init;
import com.kejin.seckill.constant.SeckillConstant;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
@Component
public class RedisPreHeat implements InitializingBean {
@Autowired
private RedisTemplate redisTemplate;
@Override
public void afterPropertiesSet() throws Exception {
Long goodsId=123456789L;redisTemplate.boundListOps(SeckillConstant.seckillStock+goodsId).leftPushAll(getAllIds(10,goodsId));
System.out.println("开始数据预热");
}
//获取秒杀商品的队列集合
public Long[] getAllIds(Integer num,Long id) {
Long[] ids = new Long[num];
for (int i = 0; i < ids.length; i++) {
ids[i] = id;
}
return ids;
}
}
SeckillService:
package com.kejin.seckill.service;
public interface SeckillService {
//下单
boolean placeOrder();
}
SeckillServiceImpl:
package com.kejin.seckill.service.impl;
import com.kejin.seckill.bean.SeckillStatus;
import com.kejin.seckill.bean.User;
import com.kejin.seckill.constant.SeckillConstant;
import com.kejin.seckill.service.SeckillService;
import com.kejin.seckill.utils.UserUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.util.Random;
@Service
public class SeckillServiceImpl implements SeckillService {
@Autowired
private RedisTemplate redisTemplate;
//下单操作
@Override
public boolean placeOrder() {
Long goodsId=123456789L;
User user=UserUtil.getCurrentUser();
SeckillStatus seckillStatus=new SeckillStatus();
seckillStatus.setStatus(1);
seckillStatus.setGoodsId(goodsId);
seckillStatus.setUserId(user.getId());
//递增,判断是否排队
Long queueCount=redisTemplate.boundHashOps(SeckillConstant.seckillOrderCount+goodsId).increment(seckillStatus.getUserId()+"",1);
if(queueCount>1){
//表示有重复抢单
return false;
}
//创建队列,记录用户秒杀信息
redisTemplate.boundListOps(SeckillConstant.seckillOrderInfo+goodsId).leftPush(seckillStatus);
//存储秒杀状态信息
redisTemplate.boundHashOps(SeckillConstant.seckillOrderStatus+goodsId).put(seckillStatus.getUserId()+"",seckillStatus);
//异步处理订单
createOrder(goodsId);
return true;
}
//异步多线程创建订单
@Async
public void createOrder(Long goodsId){
SeckillStatus seckillStatus= (SeckillStatus) redisTemplate.boundListOps(SeckillConstant.seckillOrderInfo+goodsId).rightPop();
Object goodsIdObj = redisTemplate.boundListOps(SeckillConstant.seckillStock+goodsId).rightPop();
if(null==goodsIdObj){
//代表没有库存了
System.out.println(seckillStatus.getGoodsId()+"没有库存了");
}else{
//开始下单
//修改秒杀状态信息
//创建订单后,将订单记录保存到redis中
Random random = new Random();
seckillStatus.setOrderId((long) random.nextInt(100));
seckillStatus.setStatus(2);
redisTemplate.boundHashOps(SeckillConstant.seckillOrderStatus+goodsId).put(seckillStatus.getUserId()+"",seckillStatus);
redisTemplate.boundHashOps(SeckillConstant.seckillOrderSuccess+goodsId).put(seckillStatus.getUserId()+"",seckillStatus);
}
}
}
UserUtil:
package com.kejin.seckill.utils;
import com.kejin.seckill.bean.User;
import java.util.Random;
public class UserUtil {
public static User getCurrentUser(){
Random random = new Random();
User user=new User();
user.setId((long) random.nextInt(100));
user.setUserName("张三"+random.nextInt(100));
return user;
}
}
application:
package com.kejin.seckill;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
@SpringBootApplication
@EnableAsync
public class SeckillApplication {
public static void main(String[] args) {
SpringApplication.run(SeckillApplication.class, args);
}
}
ThreadPoolTaskConfig:
package com.kejin.seckill.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;
@Component
public class RedisCacheConfig {
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(redisConnectionFactory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
//om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
application.properties:
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=127.0.0.1
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
项目结构: