java rabbitmq 并发_Java秒杀实战 (六) 服务级高并发秒杀优化(RabbitMQ+接口优化)...

转自:https://blog.csdn.net/qq_41305266/article/details/81146716

一、思路:减少数据库访问

1.系统初始化,把商品库存数量加载到Redis

2.收到请求,Redis预减库存,库存不足,直接返回,否则进入3

3.请求入队,立即返回排队中

4.请求出队,生成订单,减少库存

5.客户端轮询,是否秒杀成功

二、安装RabbitMQ及其相关依赖

下载erlang

https://www.erlang.org/downloads

61bd7799fe2f8ec831ccc605229a7d5e.png

下载rabbitMQ

f6ca59c64ba7ae0fb1bc5f9cf8a2cde5.png

安装相关依赖

yum install ncurses-devel

tar xf otp_src_21.0.tar.gz

cd otp_src_21.0

./configure --prefix=/usr/local/erlang21 --without-javac

make -j 4

make install

验证安装是否成功

ab58da794cb06e7bca64afbd63b66576.png

yum install python -y

yum install xmlto -y

yum install python-simplejson -y

xz -d rabbitmq-server-generic-unix-3.7.7.tar.xz

tar xf rabbitmq-server-generic-unix-3.7.7.tar

mv rabbitmq_server-3.7.7 /usr/local/rabbitmq

vim /etc/profile

在最后一行添加 export PATH=$PATH:/usr/local/erlang21/bin:/usr/local/rabbitmq/sbin

source /etc/profile

为了使guest用户让远程也可以访问,需要加入以下配置文件及内容

vim /usr/local/rabbitmq/etc/rabbitmq/rabbitmq.config

[{rabbit, [{loopback_users, []}]}].

重启rabbitmq使其生效。

三、SpringBoot集成RabbitMQ

pom文件引入依赖

org.springframework.boot

spring-boot-starter-amqp

application.properties添加相关配置

#rabbitmq

spring.rabbitmq.host=120.78.235.152

spring.rabbitmq.port=5672

spring.rabbitmq.username=guest

spring.rabbitmq.password=guest

spring.rabbitmq.virtual-host=/

#\u6D88\u8D39\u8005\u6570\u91CF

spring.rabbitmq.listener.simple.concurrency= 10

spring.rabbitmq.listener.simple.max-concurrency= 10

#\u6D88\u8D39\u8005\u6BCF\u6B21\u4ECE\u961F\u5217\u83B7\u53D6\u7684\u6D88\u606F\u6570\u91CF

spring.rabbitmq.listener.simple.prefetch= 1

#\u6D88\u8D39\u8005\u81EA\u52A8\u542F\u52A8

spring.rabbitmq.listener.simple.auto-startup=true

#\u6D88\u8D39\u5931\u8D25\uFF0C\u81EA\u52A8\u91CD\u65B0\u5165\u961F

spring.rabbitmq.listener.simple.default-requeue-rejected= true

#\u542F\u7528\u53D1\u9001\u91CD\u8BD5

spring.rabbitmq.template.retry.enabled=true

spring.rabbitmq.template.retry.initial-interval=1000

spring.rabbitmq.template.retry.max-attempts=3

spring.rabbitmq.template.retry.max-interval=10000

spring.rabbitmq.template.retry.multiplier=1.0

添加配置类

package com.wings.seckill.config;

import org.springframework.amqp.core.Queue;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

@Configuration

public class MQConfig {

public static final String QUEUE = "queue";

@Bean

public Queue queue(){

return new Queue(QUEUE, true);

}

}

发送者

package com.wings.seckill.rabbitmq;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.amqp.core.AmqpTemplate;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import com.wings.seckill.config.MQConfig;

import com.wings.seckill.redis.RedisService;

@Service

public class MQSender {

private Logger logger = LoggerFactory.getLogger(MQSender.class);

@Autowired

private RedisService redisService;

@Autowired

private AmqpTemplate amqpTemplate;

/**

* Direct 模式交换机

* @param obj

*/

public void send(Object obj){

String msg = redisService.beanToString(obj);

logger.info("sender send:" + msg);

amqpTemplate.convertAndSend(MQConfig.QUEUE, msg);

}

}

接收者

package com.wings.seckill.rabbitmq;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.amqp.rabbit.annotation.RabbitListener;

import org.springframework.stereotype.Service;

import com.wings.seckill.config.MQConfig;

@Service

public class MQReceiver {

private Logger logger = LoggerFactory.getLogger(MQReceiver.class);

@RabbitListener(queues = MQConfig.QUEUE)

public void receive(String msg){

logger.info("receive:" + msg);

}

}

DemoController添加以下测试方法

@RequestMapping("/mq")

@ResponseBody

public Result mq() {

mqSender.send("Wings you're the hero,路飞是成为海贼王的男人!");

return Result.success(true);

}

结果如下

2018-07-22 07:46:58.224  INFO 8624 --- [nio-8080-exec-6] com.wings.seckill.rabbitmq.MQSender      : sender send:Wings you're the hero,路飞是成为海贼王的男人!

2018-07-22 07:46:58.235  INFO 8624 --- [cTaskExecutor-1] com.wings.seckill.rabbitmq.MQReceiver    : receive:Wings you're the hero,路飞是成为海贼王的男人!

topic模式

配置类添加以下配置方法

public static final String TOPIC_QUEUE1 = "topic.queue1";

public static final String TOPIC_QUEUE2 = "topic.queue2";

public static final String TOPIC_EXCHANGE = "topicExchage";;

@Bean

public Queue topQueue1(){

return new Queue(TOPIC_QUEUE1, true);

}

@Bean

public Queue topQueue2(){

return new Queue(TOPIC_QUEUE2, true);

}

@Bean

public TopicExchange topicExchange(){

return new TopicExchange(TOPIC_EXCHANGE);

}

@Bean

public Binding topicBind1(){

return BindingBuilder.bind(topQueue1()).to(topicExchange()).with("topic.key1");

}

@Bean

public Binding topicBind2(){

return BindingBuilder.bind(topQueue2()).to(topicExchange()).with("topic.#");

}

发送者添加以下方法

public void sendTopic(Object message) {

String msg = redisService.beanToString(message);

logger.info("send topic message:" + msg);

amqpTemplate.convertAndSend(MQConfig.TOPIC_EXCHANGE, "topic.key1", msg + "1");

amqpTemplate.convertAndSend(MQConfig.TOPIC_EXCHANGE, "topic.key2", msg + "2");

}

接受者添加以下方法

@RabbitListener(queues = MQConfig.TOPIC_QUEUE1)

public void receiveTopic1(String msg){

logger.info("receiveTopic1:" + msg);

}

@RabbitListener(queues = MQConfig.TOPIC_QUEUE2)

public void receiveTopic2(String msg){

logger.info("receiveTopic2:" + msg);

}

结果如下:

fanout模式(广播模式)

配置类添加以下配置方法

@Bean

public FanoutExchange fanoutExchange(){

return new FanoutExchange(FANOUT_EXCHANGE);

}

@Bean

public Binding fanoutBind1(){

return BindingBuilder.bind(topQueue1()).to(fanoutExchange());

}

@Bean

public Binding fanoutBind2(){

return BindingBuilder.bind(topQueue2()).to(fanoutExchange());

}

发送者添加以下方法

public void sendFanout(Object message) {

String msg = redisService.beanToString(message);

logger.info("send fanout message:" + msg);

amqpTemplate.convertAndSend(MQConfig.FANOUT_EXCHANGE, "", msg);

}

结果如下:

a7eaf09621abc2bb1fc4eef39314b440.png

配置类添加以下配置方法

@Bean

public Queue headersQueue(){

return new Queue(HEADERS_QUEUE, true);

}

@Bean

public HeadersExchange headersExchange(){

return new HeadersExchange(HEADERS_EXCHANGE);

}

@Bean

public Binding headerBind(){

Map map = new HashMap();

map.put("header1", "value1");

map.put("header2", "value2");

return BindingBuilder.bind(headersQueue()).to(headersExchange()).whereAll(map).match();

}

headers模式

发送者添加以下方法

public void sendHeaders(Object message) {

String msg = redisService.beanToString(message);

logger.info("send sendHeaders message:" + msg);

MessageProperties props = new MessageProperties();

props.setHeader("header1", "value1");

props.setHeader("header2", "value2");

Message obj = new Message(msg.getBytes(), props);

amqpTemplate.convertAndSend(MQConfig.HEADERS_EXCHANGE, "", obj);

}

接收者添加以下方法

@RabbitListener(queues = MQConfig.HEADERS_QUEUE)

public void receiveHeaders(byte[] msg){

logger.info("receiveHeaders:" + new String(msg));

}

结果如下:

23b723b250efa84ce648248f9b9ede08.png

package com.wings.seckill.controller;

import java.util.HashMap;

import java.util.List;

import org.springframework.beans.factory.InitializingBean;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Controller;

import org.springframework.ui.Model;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.bind.annotation.RequestParam;

import org.springframework.web.bind.annotation.ResponseBody;

import com.wings.seckill.domain.SeckillOrder;

import com.wings.seckill.domain.SeckillUser;

import com.wings.seckill.rabbitmq.MQSender;

import com.wings.seckill.rabbitmq.SeckillMessage;

import com.wings.seckill.redis.GoodsKey;

import com.wings.seckill.redis.OrderKey;

import com.wings.seckill.redis.RedisService;

import com.wings.seckill.redis.SeckillKey;

import com.wings.seckill.result.CodeMsg;

import com.wings.seckill.result.Result;

import com.wings.seckill.service.GoodsService;

import com.wings.seckill.service.OrderService;

import com.wings.seckill.service.SeckillService;

import com.wings.seckill.service.SeckillUserService;

import com.wings.seckill.vo.GoodsVo;

@Controller

@RequestMapping("/seckill")

public class SeckillController implements InitializingBean{

@Autowired

SeckillUserService userService;

@Autowired

RedisService redisService;

@Autowired

GoodsService goodsService;

@Autowired

OrderService orderService;

@Autowired

SeckillService seckillService;

@Autowired

MQSender sender;

private HashMap localOverMap = new HashMap();

@Override

public void afterPropertiesSet() throws Exception {

List goodsList = goodsService.listGoodsVo();

if(goodsList == null) {

return;

}

for(GoodsVo goods : goodsList) {

redisService.set(GoodsKey.getSeckillGoodsStock, ""+goods.getId(), goods.getStockCount());

localOverMap.put(goods.getId(), false);

}

}

@RequestMapping(value = "/do_seckill", method = RequestMethod.POST)

@ResponseBody

public Result list(Model model, SeckillUser user, @RequestParam("goodsId") long goodsId) {

model.addAttribute("user", user);

if(user == null) {

return Result.error(CodeMsg.SESSION_ERROR);

}

//内存标记,减少redis访问

boolean over = localOverMap.get(goodsId);

if(over) {

return Result.error(CodeMsg.SECKill_OVER);

}

//预减库存

long stock = redisService.decr(GoodsKey.getSeckillGoodsStock, ""+goodsId);

if(stock < 0) {

localOverMap.put(goodsId, true);

return Result.error(CodeMsg.SECKill_OVER);

}

//判断是否已经秒杀到了

SeckillOrder order = orderService.getSeckillOrderByUserIdGoodsId(user.getId(), goodsId);

if(order != null) {

return Result.error(CodeMsg.REPEATE_SECKILL);

}

//入队

SeckillMessage mm = new SeckillMessage();

mm.setUser(user);

mm.setGoodsId(goodsId);

sender.sendSeckillMessage(mm);

return Result.success(0);//排队中

}

@RequestMapping(value="/reset", method=RequestMethod.GET)

@ResponseBody

public Result reset(Model model) {

List goodsList = goodsService.listGoodsVo();

for(GoodsVo goods : goodsList) {

goods.setStockCount(10);

redisService.set(GoodsKey.getSeckillGoodsStock, ""+goods.getId(), 10);

localOverMap.put(goods.getId(), false);

}

redisService.delete(OrderKey.getSeckillOrderByUidGid);

redisService.delete(SeckillKey.isGoodsOver);

seckillService.reset(goodsList);

return Result.success(true);

}

/**

* orderId:成功

* -1:秒杀失败

* 0: 排队中

* */

@RequestMapping(value="/result", method=RequestMethod.GET)

@ResponseBody

public Result seckillResult(Model model,SeckillUser user,

@RequestParam("goodsId")long goodsId) {

model.addAttribute("user", user);

if(user == null) {

return Result.error(CodeMsg.SESSION_ERROR);

}

long result =seckillService.getSeckillResult(user.getId(), goodsId);

return Result.success(result);

}

}

package com.wings.seckill.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import org.springframework.transaction.annotation.Transactional;

import com.wings.seckill.domain.OrderInfo;

import com.wings.seckill.domain.SeckillOrder;

import com.wings.seckill.domain.SeckillUser;

import com.wings.seckill.redis.RedisService;

import com.wings.seckill.redis.SeckillKey;

import com.wings.seckill.vo.GoodsVo;

@Service

public class SeckillService {

@Autowired

GoodsService goodsService;

@Autowired

OrderService orderService;

@Autowired

RedisService redisService;

@Transactional

public OrderInfo seckill(SeckillUser user, GoodsVo goods) {

//减库存 下订单 写入秒杀订单

boolean success = goodsService.reduceStock(goods);

if(success) {

//order_info maiosha_order

return orderService.createOrder(user, goods);

}else {

setGoodsOver(goods.getId());

return null;

}

}

public long getSeckillResult(Long userId, long goodsId) {

SeckillOrder order = orderService.getSeckillOrderByUserIdGoodsId(userId, goodsId);

if(order != null) {//秒杀成功

return order.getOrderId();

}else {

boolean isOver = getGoodsOver(goodsId);

if(isOver) {

return -1;

}else {

return 0;

}

}

}

private void setGoodsOver(Long goodsId) {

redisService.set(SeckillKey.isGoodsOver, ""+goodsId, true);

}

private boolean getGoodsOver(long goodsId) {

return redisService.exists(SeckillKey.isGoodsOver, ""+goodsId);

}

public void reset(List goodsList) {

goodsService.resetStock(goodsList);

orderService.deleteOrders();

}

}

package com.wings.seckill.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import com.wings.seckill.dao.GoodsDao;

import com.wings.seckill.domain.SeckillGoods;

import com.wings.seckill.vo.GoodsVo;

@Service

public class GoodsService {

@Autowired

GoodsDao goodsDao;

public List listGoodsVo(){

return goodsDao.listGoodsVo();

}

public GoodsVo getGoodsVoByGoodsId(long goodsId) {

return goodsDao.getGoodsVoByGoodsId(goodsId);

}

public boolean reduceStock(GoodsVo goods) {

SeckillGoods g = new SeckillGoods();

g.setGoodsId(goods.getId());

int ret = goodsDao.reduceStock(g);

return ret > 0;

}

public void resetStock(List goodsList) {

for(GoodsVo goods : goodsList ) {

SeckillGoods g = new SeckillGoods();

g.setGoodsId(goods.getId());

g.setStockCount(goods.getStockCount());

goodsDao.resetStock(g);

}

}

}

package com.wings.seckill.dao;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;

import org.apache.ibatis.annotations.Param;

import org.apache.ibatis.annotations.Select;

import org.apache.ibatis.annotations.Update;

import com.wings.seckill.domain.SeckillGoods;

import com.wings.seckill.vo.GoodsVo;

@Mapper

public interface GoodsDao {

@Select("select g.*,mg.stock_count, mg.start_date, mg.end_date,mg.seckill_price from seckill_goods mg left join goods g on mg.goods_id = g.id")

public List listGoodsVo();

@Select("select g.*,mg.stock_count, mg.start_date, mg.end_date,mg.seckill_price from seckill_goods mg left join goods g on mg.goods_id = g.id where g.id = #{goodsId}")

public GoodsVo getGoodsVoByGoodsId(@Param("goodsId")long goodsId);

@Update("update seckill_goods set stock_count = stock_count - 1 where goods_id = #{goodsId} and stock_count > 0")

public int reduceStock(SeckillGoods g);

@Update("update seckill_goods set stock_count = #{stockCount} where goods_id = #{goodsId}")

public int resetStock(SeckillGoods g);

}

package com.wings.seckill.service;

import java.util.Date;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import org.springframework.transaction.annotation.Transactional;

import com.wings.seckill.dao.OrderDao;

import com.wings.seckill.domain.OrderInfo;

import com.wings.seckill.domain.SeckillOrder;

import com.wings.seckill.domain.SeckillUser;

import com.wings.seckill.redis.OrderKey;

import com.wings.seckill.redis.RedisService;

import com.wings.seckill.vo.GoodsVo;

@Service

public class OrderService {

@Autowired

OrderDao orderDao;

@Autowired

RedisService redisService;

public SeckillOrder getSeckillOrderByUserIdGoodsId(long userId, long goodsId) {

return redisService.get(OrderKey.getSeckillOrderByUidGid, ""+userId+"_"+goodsId, SeckillOrder.class);

}

public OrderInfo getOrderById(long orderId) {

return orderDao.getOrderById(orderId);

}

@Transactional

public OrderInfo createOrder(SeckillUser user, GoodsVo goods) {

OrderInfo orderInfo = new OrderInfo();

orderInfo.setCreateDate(new Date());

orderInfo.setDeliveryAddrId(0L);

orderInfo.setGoodsCount(1);

orderInfo.setGoodsId(goods.getId());

orderInfo.setGoodsName(goods.getGoodsName());

orderInfo.setGoodsPrice(goods.getSeckillPrice());

orderInfo.setOrderChannel(1);

orderInfo.setStatus(0);

orderInfo.setUserId(user.getId());

orderDao.insert(orderInfo);

SeckillOrder seckillOrder = new SeckillOrder();

seckillOrder.setGoodsId(goods.getId());

seckillOrder.setOrderId(orderInfo.getId());

seckillOrder.setUserId(user.getId());

orderDao.insertSeckillOrder(seckillOrder);

redisService.set(OrderKey.getSeckillOrderByUidGid, ""+user.getId()+"_"+goods.getId(), seckillOrder);

return orderInfo;

}

public void deleteOrders() {

orderDao.deleteOrders();

orderDao.deleteSeckillOrders();

}

}

package com.wings.seckill.dao;

import org.apache.ibatis.annotations.Delete;

import org.apache.ibatis.annotations.Insert;

import org.apache.ibatis.annotations.Mapper;

import org.apache.ibatis.annotations.Param;

import org.apache.ibatis.annotations.Select;

import org.apache.ibatis.annotations.SelectKey;

import com.wings.seckill.domain.OrderInfo;

import com.wings.seckill.domain.SeckillOrder;

@Mapper

public interface OrderDao {

@Select("select * from seckill_order where user_id=#{userId} and goods_id=#{goodsId}")

public SeckillOrder getSeckillOrderByUserIdGoodsId(@Param("userId")long userId, @Param("goodsId")long goodsId);

@Insert("insert into order_info(user_id, goods_id, goods_name, goods_count, goods_price, order_channel, status, create_date)values("

+ "#{userId}, #{goodsId}, #{goodsName}, #{goodsCount}, #{goodsPrice}, #{orderChannel},#{status},#{createDate} )")

@SelectKey(keyColumn="id", keyProperty="id", resultType=long.class, before=false, statement="select last_insert_id()")

public long insert(OrderInfo orderInfo);

@Insert("insert into seckill_order (user_id, goods_id, order_id)values(#{userId}, #{goodsId}, #{orderId})")

public int insertSeckillOrder(SeckillOrder seckillOrder);

@Select("select * from order_info where id = #{orderId}")

public OrderInfo getOrderById(@Param("orderId") long orderId);

@Delete("delete from order_info")

public void deleteOrders();

@Delete("delete from seckill_order")

public void deleteSeckillOrders();

}

package com.wings.seckill.redis;

import java.util.ArrayList;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;

import redis.clients.jedis.Jedis;

import redis.clients.jedis.JedisPool;

import redis.clients.jedis.ScanParams;

import redis.clients.jedis.ScanResult;

@Service

public class RedisService {

@Autowired

JedisPool jedisPool;

/**

* 获取当个对象

* */

public T get(KeyPrefix prefix, String key, Class clazz) {

Jedis jedis = null;

try {

jedis = jedisPool.getResource();

//生成真正的key

String realKey = prefix.getPrefix() + key;

String str = jedis.get(realKey);

T t = stringToBean(str, clazz);

return t;

}finally {

returnToPool(jedis);

}

}

/**

* 设置对象

* */

public boolean set(KeyPrefix prefix, String key, T value) {

Jedis jedis = null;

try {

jedis = jedisPool.getResource();

String str = beanToString(value);

if(str == null || str.length() <= 0) {

return false;

}

//生成真正的key

String realKey = prefix.getPrefix() + key;

int seconds = prefix.expireSeconds();

if(seconds <= 0) {

jedis.set(realKey, str);

}else {

jedis.setex(realKey, seconds, str);

}

return true;

}finally {

returnToPool(jedis);

}

}

/**

* 判断key是否存在

* */

public boolean exists(KeyPrefix prefix, String key) {

Jedis jedis = null;

try {

jedis = jedisPool.getResource();

//生成真正的key

String realKey = prefix.getPrefix() + key;

return jedis.exists(realKey);

}finally {

returnToPool(jedis);

}

}

/**

* 删除

* */

public boolean delete(KeyPrefix prefix, String key) {

Jedis jedis = null;

try {

jedis = jedisPool.getResource();

//生成真正的key

String realKey = prefix.getPrefix() + key;

long ret = jedis.del(realKey);

return ret > 0;

}finally {

returnToPool(jedis);

}

}

/**

* 增加值

* */

public Long incr(KeyPrefix prefix, String key) {

Jedis jedis = null;

try {

jedis = jedisPool.getResource();

//生成真正的key

String realKey = prefix.getPrefix() + key;

return jedis.incr(realKey);

}finally {

returnToPool(jedis);

}

}

/**

* 减少值

* */

public Long decr(KeyPrefix prefix, String key) {

Jedis jedis = null;

try {

jedis = jedisPool.getResource();

//生成真正的key

String realKey = prefix.getPrefix() + key;

return jedis.decr(realKey);

}finally {

returnToPool(jedis);

}

}

public boolean delete(KeyPrefix prefix) {

if(prefix == null) {

return false;

}

List keys = scanKeys(prefix.getPrefix());

if(keys==null || keys.size() <= 0) {

return true;

}

Jedis jedis = null;

try {

jedis = jedisPool.getResource();

jedis.del(keys.toArray(new String[0]));

return true;

} catch (final Exception e) {

e.printStackTrace();

return false;

} finally {

if(jedis != null) {

jedis.close();

}

}

}

public List scanKeys(String key) {

Jedis jedis = null;

try {

jedis = jedisPool.getResource();

List keys = new ArrayList();

String cursor = "0";

ScanParams sp = new ScanParams();

sp.match("*"+key+"*");

sp.count(100);

do{

ScanResult ret = jedis.scan(cursor, sp);

List result = ret.getResult();

if(result!=null && result.size() > 0){

keys.addAll(result);

}

//再处理cursor

cursor = ret.getStringCursor();

}while(!cursor.equals("0"));

return keys;

} finally {

if (jedis != null) {

jedis.close();

}

}

}

public static String beanToString(T value) {

if(value == null) {

return null;

}

Class> clazz = value.getClass();

if(clazz == int.class || clazz == Integer.class) {

return ""+value;

}else if(clazz == String.class) {

return (String)value;

}else if(clazz == long.class || clazz == Long.class) {

return ""+value;

}else {

return JSON.toJSONString(value);

}

}

@SuppressWarnings("unchecked")

public static T stringToBean(String str, Class clazz) {

if(str == null || str.length() <= 0 || clazz == null) {

return null;

}

if(clazz == int.class || clazz == Integer.class) {

return (T)Integer.valueOf(str);

}else if(clazz == String.class) {

return (T)str;

}else if(clazz == long.class || clazz == Long.class) {

return (T)Long.valueOf(str);

}else {

return JSON.toJavaObject(JSON.parseObject(str), clazz);

}

}

private void returnToPool(Jedis jedis) {

if(jedis != null) {

jedis.close();

}

}

}

package com.wings.seckill.rabbitmq;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.amqp.rabbit.annotation.RabbitListener;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import com.wings.seckill.config.MQConfig;

import com.wings.seckill.domain.SeckillOrder;

import com.wings.seckill.domain.SeckillUser;

import com.wings.seckill.redis.RedisService;

import com.wings.seckill.service.GoodsService;

import com.wings.seckill.service.OrderService;

import com.wings.seckill.service.SeckillService;

import com.wings.seckill.vo.GoodsVo;

@Service

public class MQReceiver {

private Logger logger = LoggerFactory.getLogger(MQReceiver.class);

@Autowired

RedisService redisService;

@Autowired

GoodsService goodsService;

@Autowired

OrderService orderService;

@Autowired

SeckillService seckillService;

@RabbitListener(queues=MQConfig.SECKILL_QUEUE)

public void receiveSeckill(String message) {

logger.info("receive message:"+message);

SeckillMessage mm = redisService.stringToBean(message, SeckillMessage.class);

SeckillUser user = mm.getUser();

long goodsId = mm.getGoodsId();

GoodsVo goods = goodsService.getGoodsVoByGoodsId(goodsId);

int stock = goods.getStockCount();

if(stock <= 0) {

return;

}

//判断是否已经秒杀到了

SeckillOrder order = orderService.getSeckillOrderByUserIdGoodsId(user.getId(), goodsId);

if(order != null) {

return;

}

//减库存 下订单 写入秒杀订单

seckillService.seckill(user, goods);

}

@RabbitListener(queues = MQConfig.QUEUE)

public void receive(String msg){

logger.info("receive:" + msg);

}

@RabbitListener(queues = MQConfig.TOPIC_QUEUE1)

public void receiveTopic1(String msg){

logger.info("receiveTopic1:" + msg);

}

@RabbitListener(queues = MQConfig.TOPIC_QUEUE2)

public void receiveTopic2(String msg){

logger.info("receiveTopic2:" + msg);

}

@RabbitListener(queues = MQConfig.HEADERS_QUEUE)

public void receiveHeaders(byte[] msg){

logger.info("receiveHeaders:" + new String(msg));

}

}

package com.wings.seckill.rabbitmq;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.amqp.core.AmqpTemplate;

import org.springframework.amqp.core.Message;

import org.springframework.amqp.core.MessageProperties;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import com.wings.seckill.config.MQConfig;

import com.wings.seckill.redis.RedisService;

@Service

public class MQSender {

private Logger logger = LoggerFactory.getLogger(MQSender.class);

@Autowired

private RedisService redisService;

@Autowired

private AmqpTemplate amqpTemplate;

public void sendSeckillMessage(SeckillMessage mm) {

String msg = redisService.beanToString(mm);

logger.info("send message:"+msg);

amqpTemplate.convertAndSend(MQConfig.SECKILL_QUEUE, msg);

}

/**

* Direct 模式交换机

*

* @param obj

*/

public void send(Object obj) {

String msg = redisService.beanToString(obj);

logger.info("sender send:" + msg);

amqpTemplate.convertAndSend(MQConfig.QUEUE, msg);

}

public void sendTopic(Object message) {

String msg = redisService.beanToString(message);

logger.info("send topic message:" + msg);

amqpTemplate.convertAndSend(MQConfig.TOPIC_EXCHANGE, "topic.key1", msg + "1");

amqpTemplate.convertAndSend(MQConfig.TOPIC_EXCHANGE, "topic.key2", msg + "2");

}

public void sendFanout(Object message) {

String msg = redisService.beanToString(message);

logger.info("send fanout message:" + msg);

amqpTemplate.convertAndSend(MQConfig.FANOUT_EXCHANGE, "", msg);

}

public void sendHeaders(Object message) {

String msg = redisService.beanToString(message);

logger.info("send sendHeaders message:" + msg);

MessageProperties props = new MessageProperties();

props.setHeader("header1", "value1");

props.setHeader("header2", "value2");

Message obj = new Message(msg.getBytes(), props);

amqpTemplate.convertAndSend(MQConfig.HEADERS_EXCHANGE, "", obj);

}

}

商品详情
秒杀商品详情

您还没有登录,请登陆后再操作

没有收货地址的提示。。。

商品名称
商品图片
秒杀开始时间

立即秒杀

商品原价
秒杀价
库存数量

function getSeckillResult(goodsId){

g_showLoading();

$.ajax({

url:"/seckill/result",

type:"GET",

data:{

goodsId:$("#goodsId").val(),

},

success:function(data){

if(data.code == 0){

var result = data.data;

if(result < 0){

layer.msg("对不起,秒杀失败");

}else if(result == 0){//继续轮询

setTimeout(function(){

getSeckillResult(goodsId);

}, 50);

}else{

layer.confirm("恭喜你,秒杀成功!查看订单?", {btn:["确定","取消"]},

function(){

window.location.href="/order_detail.htm?orderId="+result;

},

function(){

layer.closeAll();

});

}

}else{

layer.msg(data.msg);

}

},

error:function(){

layer.msg("客户端请求有误");

}

});

}

function doSeckill(){

$.ajax({

url:"/seckill/do_seckill",

type:"POST",

data:{

goodsId:$("#goodsId").val(),

},

success:function(data){

if(data.code == 0){

//window.location.href="/order_detail.htm?orderId="+data.data.id;

getSeckillResult($("#goodsId").val());

}else{

layer.msg(data.msg);

}

},

error:function(){

layer.msg("客户端请求有误");

}

});

}

function render(detail){

var seckillStatus = detail.seckillStatus;

var remainSeconds = detail.remainSeconds;

var goods = detail.goods;

var user = detail.user;

if(user){

$("#userTip").hide();

}

$("#goodsName").text(goods.goodsName);

$("#goodsImg").attr("src", goods.goodsImg);

$("#startTime").text(new Date(goods.startDate).format("yyyy-MM-dd hh:mm:ss"));

$("#remainSeconds").val(remainSeconds);

$("#goodsId").val(goods.id);

$("#goodsPrice").text(goods.goodsPrice);

$("#seckillPrice").text(goods.seckillPrice);

$("#stockCount").text(goods.stockCount);

countDown();

}

$(function(){

//countDown();

getDetail();

});

function getDetail(){

var goodsId = g_getQueryString("goodsId");

$.ajax({

url:"/goods/detail/"+goodsId,

type:"GET",

success:function(data){

if(data.code == 0){

render(data.data);

}else{

layer.msg(data.msg);

}

},

error:function(){

layer.msg("客户端请求有误");

}

});

}

function countDown(){

var remainSeconds = $("#remainSeconds").val();

var timeout;

if(remainSeconds > 0){//秒杀还没开始,倒计时

$("#buyButton").attr("disabled", true);

$("#seckillTip").html("秒杀倒计时:"+remainSeconds+"秒");

timeout = setTimeout(function(){

$("#countDown").text(remainSeconds - 1);

$("#remainSeconds").val(remainSeconds - 1);

countDown();

},1000);

}else if(remainSeconds == 0){//秒杀进行中

$("#buyButton").attr("disabled", false);

if(timeout){

clearTimeout(timeout);

}

$("#seckillTip").html("秒杀进行中");

}else{//秒杀已经结束

$("#buyButton").attr("disabled", true);

$("#seckillTip").html("秒杀已经结束");

}

}

最终优化效果如下:

97c5a1e3f1da41bc07623184cee8cb53.png

比原来提高了3倍QPS!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值